blob: e556af352fac6af7d337f2a7d5193764216303da [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 + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000038LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000039
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000040try:
41 from signal import SIGTERM
42except ImportError:
43 SIGTERM = 15
44
Chui Tey5d2af632002-05-26 13:36:41 +000045# Change warnings module to write to sys.__stderr__
46try:
47 import warnings
48except ImportError:
49 pass
50else:
51 def idle_showwarning(message, category, filename, lineno):
52 file = sys.__stderr__
53 file.write(warnings.formatwarning(message, category, filename, lineno))
54 warnings.showwarning = idle_showwarning
55
Kurt B. Kaiser81885592002-11-29 22:10:53 +000056def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000057 """Extend linecache.checkcache to preserve the <pyshell#...> entries
58
Kurt B. Kaiser81885592002-11-29 22:10:53 +000059 Rather than repeating the linecache code, patch it to save the pyshell#
60 entries, call the original linecache.checkcache(), and then restore the
61 saved entries. Assigning the orig_checkcache keyword arg freezes its value
62 at definition time to the (original) method linecache.checkcache(), i.e.
63 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000064
65 """
David Scherer7aced172000-08-15 01:13:23 +000066 cache = linecache.cache
67 save = {}
68 for filename in cache.keys():
69 if filename[:1] + filename[-1:] == '<>':
70 save[filename] = cache[filename]
71 orig_checkcache()
72 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000073
Kurt B. Kaiser81885592002-11-29 22:10:53 +000074# Patch linecache.checkcache():
75linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000076
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077
David Scherer7aced172000-08-15 01:13:23 +000078class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000079 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000080
David Scherer7aced172000-08-15 01:13:23 +000081 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000082 self.breakpoints = []
David Scherer7aced172000-08-15 01:13:23 +000083 apply(EditorWindow.__init__, (self,) + args)
84 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000085 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +000086 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
87
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000088 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
89 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +000090 # whenever a file is changed, restore breakpoints
91 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000092 def filename_changed_hook(old_hook=self.io.filename_change_hook,
93 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +000094 self.restore_file_breaks()
95 old_hook()
96 self.io.set_filename_change_hook(filename_changed_hook)
97
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000098 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
99 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000100
Chui Teya2adb0f2002-11-04 22:14:54 +0000101 def set_breakpoint(self, lineno):
102 text = self.text
103 filename = self.io.filename
104 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
105 try:
106 i = self.breakpoints.index(lineno)
107 except ValueError: # only add if missing, i.e. do once
108 self.breakpoints.append(lineno)
109 try: # update the subprocess debugger
110 debug = self.flist.pyshell.interp.debugger
111 debug.set_breakpoint_here(filename, lineno)
112 except: # but debugger may not be active right now....
113 pass
114
David Scherer7aced172000-08-15 01:13:23 +0000115 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000116 text = self.text
117 filename = self.io.filename
118 if not filename:
119 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000120 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000121 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000122 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000123
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000124 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000125 text = self.text
126 filename = self.io.filename
127 if not filename:
128 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000129 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000130 lineno = int(float(text.index("insert")))
131 try:
132 self.breakpoints.remove(lineno)
133 except:
134 pass
135 text.tag_remove("BREAK", "insert linestart",\
136 "insert lineend +1char")
137 try:
138 debug = self.flist.pyshell.interp.debugger
139 debug.clear_breakpoint_here(filename, lineno)
140 except:
141 pass
142
143 def clear_file_breaks(self):
144 if self.breakpoints:
145 text = self.text
146 filename = self.io.filename
147 if not filename:
148 text.bell()
149 return
150 self.breakpoints = []
151 text.tag_remove("BREAK", "1.0", END)
152 try:
153 debug = self.flist.pyshell.interp.debugger
154 debug.clear_file_breaks(filename)
155 except:
156 pass
157
Chui Teya2adb0f2002-11-04 22:14:54 +0000158 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000159 "Save breakpoints when file is saved"
160 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
161 # be run. The breaks are saved at that time. If we introduce
162 # a temporary file save feature the save breaks functionality
163 # needs to be re-verified, since the breaks at the time the
164 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000165 # permanent save of the file. Currently, a break introduced
166 # after a save will be effective, but not persistent.
167 # This is necessary to keep the saved breaks synched with the
168 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000169 #
170 # Breakpoints are set as tagged ranges in the text. Certain
171 # kinds of edits cause these ranges to be deleted: Inserting
172 # or deleting a line just before a breakpoint, and certain
173 # deletions prior to a breakpoint. These issues need to be
174 # investigated and understood. It's not clear if they are
175 # Tk issues or IDLE issues, or whether they can actually
176 # be fixed. Since a modified file has to be saved before it is
177 # run, and since self.breakpoints (from which the subprocess
178 # debugger is loaded) is updated during the save, the visible
179 # breaks stay synched with the subprocess even if one of these
180 # unexpected breakpoint deletions occurs.
181 breaks = self.breakpoints
182 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000183 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000184 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000185 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000186 lines = []
187 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000188 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000189 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000190 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000191 self.update_breakpoints()
192 breaks = self.breakpoints
193 if breaks:
194 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000195 new_file.close()
196
197 def restore_file_breaks(self):
198 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000199 filename = self.io.filename
200 if filename is None:
201 return
Chui Tey69371d62002-11-04 23:39:45 +0000202 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000203 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000204 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000205 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000206 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000207 for breakpoint_linenumber in breakpoint_linenumbers:
208 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000209
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 def update_breakpoints(self):
211 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000212 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000213 ranges = text.tag_ranges("BREAK")
214 linenumber_list = self.ranges_to_linenumbers(ranges)
215 self.breakpoints = linenumber_list
216
217 def ranges_to_linenumbers(self, ranges):
218 lines = []
219 for index in range(0, len(ranges), 2):
220 lineno = int(float(ranges[index]))
221 end = int(float(ranges[index+1]))
222 while lineno < end:
223 lines.append(lineno)
224 lineno += 1
225 return lines
226
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000227# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000228# def saved_change_hook(self):
229# "Extend base method - clear breaks if module is modified"
230# if not self.get_saved():
231# self.clear_file_breaks()
232# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000233
234 def _close(self):
235 "Extend base method - clear breaks when module is closed"
236 self.clear_file_breaks()
237 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000238
David Scherer7aced172000-08-15 01:13:23 +0000239
240class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000241 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000242
243 EditorWindow = PyShellEditorWindow
244
245 pyshell = None
246
247 def open_shell(self, event=None):
248 if self.pyshell:
249 self.pyshell.wakeup()
250 else:
251 self.pyshell = PyShell(self)
252 self.pyshell.begin()
253 return self.pyshell
254
255
256class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000257 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
Steven M. Gavab77d3432002-03-02 07:16:21 +0000259 def __init__(self):
260 ColorDelegator.__init__(self)
261 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000262
263 def recolorize_main(self):
264 self.tag_remove("TODO", "1.0", "iomark")
265 self.tag_add("SYNC", "1.0", "iomark")
266 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000267
Steven M. Gavab77d3432002-03-02 07:16:21 +0000268 def LoadTagDefs(self):
269 ColorDelegator.LoadTagDefs(self)
270 theme = idleConf.GetOption('main','Theme','name')
271 self.tagdefs.update({
272 "stdin": {'background':None,'foreground':None},
273 "stdout": idleConf.GetHighlight(theme, "stdout"),
274 "stderr": idleConf.GetHighlight(theme, "stderr"),
275 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000276 None: idleConf.GetHighlight(theme, "normal"),
277 })
David Scherer7aced172000-08-15 01:13:23 +0000278
David Scherer7aced172000-08-15 01:13:23 +0000279class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000280 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000281
282 def insert(self, index, chars, tags=None):
283 try:
284 if self.delegate.compare(index, "<", "iomark"):
285 self.delegate.bell()
286 return
287 except TclError:
288 pass
289 UndoDelegator.insert(self, index, chars, tags)
290
291 def delete(self, index1, index2=None):
292 try:
293 if self.delegate.compare(index1, "<", "iomark"):
294 self.delegate.bell()
295 return
296 except TclError:
297 pass
298 UndoDelegator.delete(self, index1, index2)
299
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000300
301class MyRPCClient(rpc.RPCClient):
302
303 def handle_EOF(self):
304 "Override the base class - just re-raise EOFError"
305 raise EOFError
306
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000307
David Scherer7aced172000-08-15 01:13:23 +0000308class ModifiedInterpreter(InteractiveInterpreter):
309
310 def __init__(self, tkconsole):
311 self.tkconsole = tkconsole
312 locals = sys.modules['__main__'].__dict__
313 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000314 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000315 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000316 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000317
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000318 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000319 rpcclt = None
320 rpcpid = None
321
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000322 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000323 args = self.subprocess_arglist
Chui Tey5d2af632002-05-26 13:36:41 +0000324 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000325
Tony Lowndsf53dec22002-12-20 04:24:43 +0000326 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000327 w = ['-W' + s for s in sys.warnoptions]
328 # Maybe IDLE is installed and is being accessed via sys.path,
329 # or maybe it's not installed and the idle.py script is being
330 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000331 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
332 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000333 if __name__ == 'idlelib.PyShell':
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000334 command = "__import__('idlelib.run').run.main(" + `del_exitf` +")"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000335 else:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000336 command = "__import__('run').main(" + `del_exitf` + ")"
Tony Lownds2398d572003-05-13 15:28:21 +0000337 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000338
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000339 def start_subprocess(self):
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000340 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000341 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000342 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000343 time.sleep(i)
344 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000345 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000346 break
347 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000348 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000349 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000350 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000351 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000352 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000353 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000354 # Accept the connection from the Python execution server
355 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000356 self.rpcclt.register("stdin", self.tkconsole)
357 self.rpcclt.register("stdout", self.tkconsole.stdout)
358 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000359 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000360 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000361 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000362 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000363 self.poll_subprocess()
364
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000365 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000366 if self.restarting:
367 return
368 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000369 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000370 debug = self.getdebugger()
371 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000372 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000373 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000374 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
375 except:
376 pass
377 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000378 self.rpcclt.close()
379 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000380 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000381 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000382 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000383 self.spawn_subprocess()
384 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000385 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000386 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000387 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000388 if was_executing:
389 console.write('\n')
390 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000391 halfbar = ((int(console.width) - 16) // 2) * '='
392 console.write(halfbar + ' RESTART ' + halfbar)
393 console.text.mark_set("restart", "end-1c")
394 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000395 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000396 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000397 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000398 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000399 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000400 # reload remote debugger breakpoints for all PyShellEditWindows
401 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000402 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000403
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000404 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000405 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000406
407 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000408 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000409
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000410 def kill_subprocess(self):
411 self.rpcclt.close()
412 self.unix_terminate()
413 self.tkconsole.executing = False
414 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000415
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000416 def unix_terminate(self):
417 "UNIX: make sure subprocess is terminated and collect status"
418 if hasattr(os, 'kill'):
419 try:
420 os.kill(self.rpcpid, SIGTERM)
421 except OSError:
422 # process already terminated:
423 return
424 else:
425 try:
426 os.waitpid(self.rpcpid, 0)
427 except OSError:
428 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000429
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000430 def transfer_path(self):
431 self.runcommand("""if 1:
432 import sys as _sys
433 _sys.path = %s
434 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000435 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
436 __builtins__.quit = __builtins__.exit = _msg
437 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000438 \n""" % `sys.path`)
439
Chui Tey5d2af632002-05-26 13:36:41 +0000440 active_seq = None
441
442 def poll_subprocess(self):
443 clt = self.rpcclt
444 if clt is None:
445 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000446 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000447 response = clt.pollresponse(self.active_seq, wait=0.05)
448 except (EOFError, IOError, KeyboardInterrupt):
449 # lost connection or subprocess terminated itself, restart
450 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000451 if self.tkconsole.closing:
452 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000453 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000454 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000455 if response:
456 self.tkconsole.resetoutput()
457 self.active_seq = None
458 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000459 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000460 if how == "OK":
461 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000462 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000463 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000464 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
465 self.remote_stack_viewer()
466 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000467 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
468 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000469 print >>console, errmsg, what
470 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000471 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000472 # Reschedule myself
473 if not self.tkconsole.closing:
474 self.tkconsole.text.after(self.tkconsole.pollinterval,
475 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000476
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000477 debugger = None
478
479 def setdebugger(self, debugger):
480 self.debugger = debugger
481
482 def getdebugger(self):
483 return self.debugger
484
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000485 def open_remote_stack_viewer(self):
486 """Initiate the remote stack viewer from a separate thread.
487
488 This method is called from the subprocess, and by returning from this
489 method we allow the subprocess to unblock. After a bit the shell
490 requests the subprocess to open the remote stack viewer which returns a
491 static object looking at the last exceptiopn. It is queried through
492 the RPC mechanism.
493
494 """
495 self.tkconsole.text.after(300, self.remote_stack_viewer)
496 return
497
Chui Tey5d2af632002-05-26 13:36:41 +0000498 def remote_stack_viewer(self):
499 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000500 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000501 if oid is None:
502 self.tkconsole.root.bell()
503 return
504 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
505 from TreeWidget import ScrolledCanvas, TreeNode
506 top = Toplevel(self.tkconsole.root)
507 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
508 sc.frame.pack(expand=1, fill="both")
509 node = TreeNode(sc.canvas, None, item)
510 node.expand()
511 # XXX Should GC the remote tree when closing the window
512
David Scherer7aced172000-08-15 01:13:23 +0000513 gid = 0
514
515 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000516 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000517 filename = self.stuffsource(source)
518 self.execfile(filename, source)
519
520 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000521 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000522 if source is None:
523 source = open(filename, "r").read()
524 try:
525 code = compile(source, filename, "exec")
526 except (OverflowError, SyntaxError):
527 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000528 tkerr = self.tkconsole.stderr
529 print>>tkerr, '*** Error in script or command!\n'
530 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000531 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000532 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000533 else:
534 self.runcode(code)
535
536 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000537 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000538 filename = self.stuffsource(source)
539 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000540 self.save_warnings_filters = warnings.filters[:]
541 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000542 if isinstance(source, types.UnicodeType):
543 import IOBinding
544 try:
545 source = source.encode(IOBinding.encoding)
546 except UnicodeError:
547 self.tkconsole.resetoutput()
548 self.write("Unsupported characters in input")
549 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000550 try:
551 return InteractiveInterpreter.runsource(self, source, filename)
552 finally:
553 if self.save_warnings_filters is not None:
554 warnings.filters[:] = self.save_warnings_filters
555 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000556
557 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000558 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000559 filename = "<pyshell#%d>" % self.gid
560 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000561 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000562 linecache.cache[filename] = len(source)+1, 0, lines, filename
563 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000564
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000565 def prepend_syspath(self, filename):
566 "Prepend sys.path with file's directory if not already included"
567 self.runcommand("""if 1:
568 _filename = %s
569 import sys as _sys
570 from os.path import dirname as _dirname
571 _dir = _dirname(_filename)
572 if not _dir in _sys.path:
573 _sys.path.insert(0, _dir)
574 del _filename, _sys, _dirname, _dir
575 \n""" % `filename`)
576
David Scherer7aced172000-08-15 01:13:23 +0000577 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000578 """Extend base class method: Add Colorizing
579
580 Color the offending position instead of printing it and pointing at it
581 with a caret.
582
583 """
David Scherer7aced172000-08-15 01:13:23 +0000584 text = self.tkconsole.text
585 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000586 if stuff:
587 msg, lineno, offset, line = stuff
588 if lineno == 1:
589 pos = "iomark + %d chars" % (offset-1)
590 else:
591 pos = "iomark linestart + %d lines + %d chars" % \
592 (lineno-1, offset-1)
593 text.tag_add("ERROR", pos)
594 text.see(pos)
595 char = text.get(pos)
596 if char and char in IDENTCHARS:
597 text.tag_add("ERROR", pos + " wordstart", pos)
598 self.tkconsole.resetoutput()
599 self.write("SyntaxError: %s\n" % str(msg))
600 else:
David Scherer7aced172000-08-15 01:13:23 +0000601 self.tkconsole.resetoutput()
602 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000603 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000604
605 def unpackerror(self):
606 type, value, tb = sys.exc_info()
607 ok = type is SyntaxError
608 if ok:
609 try:
610 msg, (dummy_filename, lineno, offset, line) = value
611 except:
612 ok = 0
613 if ok:
614 return msg, lineno, offset, line
615 else:
616 return None
617
618 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000619 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000620 self.tkconsole.resetoutput()
621 self.checklinecache()
622 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000623 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
624 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000625
626 def checklinecache(self):
627 c = linecache.cache
628 for key in c.keys():
629 if key[:1] + key[-1:] != "<>":
630 del c[key]
631
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000632 def display_executing_dialog(self):
633 tkMessageBox.showerror(
634 "Already executing",
635 "The Python Shell window is already executing a command; "
636 "please wait until it is finished.",
637 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000638
Chui Tey5d2af632002-05-26 13:36:41 +0000639 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000640 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000641 # The code better not raise an exception!
642 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000643 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000644 return 0
645 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000646 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000647 else:
648 exec code in self.locals
649 return 1
650
David Scherer7aced172000-08-15 01:13:23 +0000651 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000652 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000653 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000654 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000655 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000656 if self.save_warnings_filters is not None:
657 warnings.filters[:] = self.save_warnings_filters
658 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000659 debugger = self.debugger
660 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000661 self.tkconsole.beginexecuting()
662 try:
663 if not debugger and self.rpcclt is not None:
664 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
665 (code,), {})
666 elif debugger:
667 debugger.run(code, self.locals)
668 else:
669 exec code in self.locals
670 except SystemExit:
671 if tkMessageBox.askyesno(
672 "Exit?",
673 "Do you want to exit altogether?",
674 default="yes",
675 master=self.tkconsole.text):
676 raise
677 else:
678 self.showtraceback()
679 except:
David Scherer7aced172000-08-15 01:13:23 +0000680 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000681 finally:
682 if not use_subprocess:
683 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000684
685 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000686 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000687 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000688
David Scherer7aced172000-08-15 01:13:23 +0000689class PyShell(OutputWindow):
690
691 shell_title = "Python Shell"
692
693 # Override classes
694 ColorDelegator = ModifiedColorDelegator
695 UndoDelegator = ModifiedUndoDelegator
696
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000697 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000698 menu_specs = [
699 ("file", "_File"),
700 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000701 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000702 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000703 ("windows", "_Windows"),
704 ("help", "_Help"),
705 ]
David Scherer7aced172000-08-15 01:13:23 +0000706
707 # New classes
708 from IdleHistory import History
709
710 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000711 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000712 ms = self.menu_specs
713 if ms[2][0] != "shell":
714 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000715 self.interp = ModifiedInterpreter(self)
716 if flist is None:
717 root = Tk()
718 fixwordbreaks(root)
719 root.withdraw()
720 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000721 #
David Scherer7aced172000-08-15 01:13:23 +0000722 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000723 #
David Scherer7aced172000-08-15 01:13:23 +0000724 import __builtin__
725 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000726 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000727 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000728 #
David Scherer7aced172000-08-15 01:13:23 +0000729 text = self.text
730 text.configure(wrap="char")
731 text.bind("<<newline-and-indent>>", self.enter_callback)
732 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
733 text.bind("<<interrupt-execution>>", self.cancel_callback)
734 text.bind("<<beginning-of-line>>", self.home_callback)
735 text.bind("<<end-of-file>>", self.eof_callback)
736 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000737 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000738 text.bind("<<open-python-shell>>", self.flist.open_shell)
739 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000740 if use_subprocess:
741 text.bind("<<view-restart>>", self.view_restart_mark)
742 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000743 #
David Scherer7aced172000-08-15 01:13:23 +0000744 self.save_stdout = sys.stdout
745 self.save_stderr = sys.stderr
746 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000747 self.stdout = PseudoFile(self, "stdout")
748 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000749 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000750 if not use_subprocess:
751 sys.stdout = self.stdout
752 sys.stderr = self.stderr
753 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000754 #
David Scherer7aced172000-08-15 01:13:23 +0000755 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000756 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000757 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000758 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000759 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000760
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000761 reading = False
762 executing = False
763 canceled = False
764 endoffile = False
765 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000766
767 def toggle_debugger(self, event=None):
768 if self.executing:
769 tkMessageBox.showerror("Don't debug now",
770 "You can only toggle the debugger when idle",
771 master=self.text)
772 self.set_debugger_indicator()
773 return "break"
774 else:
775 db = self.interp.getdebugger()
776 if db:
777 self.close_debugger()
778 else:
779 self.open_debugger()
780
781 def set_debugger_indicator(self):
782 db = self.interp.getdebugger()
783 self.setvar("<<toggle-debugger>>", not not db)
784
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000785 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000786 pass # All we need is the variable
787
788 def close_debugger(self):
789 db = self.interp.getdebugger()
790 if db:
791 self.interp.setdebugger(None)
792 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000793 if self.interp.rpcclt:
794 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000795 self.resetoutput()
796 self.console.write("[DEBUG OFF]\n")
797 sys.ps1 = ">>> "
798 self.showprompt()
799 self.set_debugger_indicator()
800
801 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000802 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000803 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
804 self)
805 else:
806 dbg_gui = Debugger.Debugger(self)
807 self.interp.setdebugger(dbg_gui)
808 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000809 sys.ps1 = "[DEBUG ON]\n>>> "
810 self.showprompt()
811 self.set_debugger_indicator()
812
David Scherer7aced172000-08-15 01:13:23 +0000813 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000814 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000815 self.resetoutput()
816 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000817
818 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000819 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000820 self.executing = 0
821 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000822 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000823
824 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000825 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000826 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000827 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000828 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000829 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000830 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000831 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000832 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000833 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000834 self.closing = True
835 # Wait for poll_subprocess() rescheduling to stop
836 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000837
838 def close2(self):
839 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000840
841 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000842 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000843 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000844 if use_subprocess:
845 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000846 # Restore std streams
847 sys.stdout = self.save_stdout
848 sys.stderr = self.save_stderr
849 sys.stdin = self.save_stdin
850 # Break cycles
851 self.interp = None
852 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000853 self.flist.pyshell = None
854 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000855 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000856
857 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000858 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000859 return True
David Scherer7aced172000-08-15 01:13:23 +0000860
861 def short_title(self):
862 return self.shell_title
863
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000864 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000865 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000866
David Scherer7aced172000-08-15 01:13:23 +0000867 def begin(self):
868 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000869 if use_subprocess:
870 nosub = ''
871 else:
872 nosub = "==== No Subprocess ===="
873 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000874 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000875 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000876 self.showprompt()
877 import Tkinter
878 Tkinter._default_root = None
879
880 def interact(self):
881 self.begin()
882 self.top.mainloop()
883
884 def readline(self):
885 save = self.reading
886 try:
887 self.reading = 1
888 self.top.mainloop()
889 finally:
890 self.reading = save
891 line = self.text.get("iomark", "end-1c")
892 self.resetoutput()
893 if self.canceled:
894 self.canceled = 0
895 raise KeyboardInterrupt
896 if self.endoffile:
897 self.endoffile = 0
898 return ""
899 return line
900
901 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000902 return True
David Scherer7aced172000-08-15 01:13:23 +0000903
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000904 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000905 try:
906 if self.text.compare("sel.first", "!=", "sel.last"):
907 return # Active selection -- always use default binding
908 except:
909 pass
910 if not (self.executing or self.reading):
911 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000912 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000913 self.showprompt()
914 return "break"
915 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000916 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000917 if self.reading:
918 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000919 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000920 if self.interp.getdebugger():
921 self.interp.restart_subprocess()
922 else:
923 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000924 return "break"
925
926 def eof_callback(self, event):
927 if self.executing and not self.reading:
928 return # Let the default binding (delete next char) take over
929 if not (self.text.compare("iomark", "==", "insert") and
930 self.text.compare("insert", "==", "end-1c")):
931 return # Let the default binding (delete next char) take over
932 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000933 self.resetoutput()
934 self.close()
935 else:
936 self.canceled = 0
937 self.endoffile = 1
938 self.top.quit()
939 return "break"
940
941 def home_callback(self, event):
942 if event.state != 0 and event.keysym == "Home":
943 return # <Modifier-Home>; fall back to class binding
944 if self.text.compare("iomark", "<=", "insert") and \
945 self.text.compare("insert linestart", "<=", "iomark"):
946 self.text.mark_set("insert", "iomark")
947 self.text.tag_remove("sel", "1.0", "end")
948 self.text.see("insert")
949 return "break"
950
951 def linefeed_callback(self, event):
952 # Insert a linefeed without entering anything (still autoindented)
953 if self.reading:
954 self.text.insert("insert", "\n")
955 self.text.see("insert")
956 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000957 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000958 return "break"
959
960 def enter_callback(self, event):
961 if self.executing and not self.reading:
962 return # Let the default binding (insert '\n') take over
963 # If some text is selected, recall the selection
964 # (but only if this before the I/O mark)
965 try:
966 sel = self.text.get("sel.first", "sel.last")
967 if sel:
968 if self.text.compare("sel.last", "<=", "iomark"):
969 self.recall(sel)
970 return "break"
971 except:
972 pass
973 # If we're strictly before the line containing iomark, recall
974 # the current line, less a leading prompt, less leading or
975 # trailing whitespace
976 if self.text.compare("insert", "<", "iomark linestart"):
977 # Check if there's a relevant stdin range -- if so, use it
978 prev = self.text.tag_prevrange("stdin", "insert")
979 if prev and self.text.compare("insert", "<", prev[1]):
980 self.recall(self.text.get(prev[0], prev[1]))
981 return "break"
982 next = self.text.tag_nextrange("stdin", "insert")
983 if next and self.text.compare("insert lineend", ">=", next[0]):
984 self.recall(self.text.get(next[0], next[1]))
985 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000986 # No stdin mark -- just get the current line, less any prompt
987 line = self.text.get("insert linestart", "insert lineend")
988 last_line_of_prompt = sys.ps1.split('\n')[-1]
989 if line.startswith(last_line_of_prompt):
990 line = line[len(last_line_of_prompt):]
991 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000992 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000993 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000994 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000995 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000996 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000997 # If we're in the current input and there's only whitespace
998 # beyond the cursor, erase that whitespace first
999 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001000 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001001 self.text.delete("insert", "end-1c")
1002 # If we're in the current input before its last line,
1003 # insert a newline right at the insert point
1004 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001005 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001006 return "break"
1007 # We're in the last line; append a newline and submit it
1008 self.text.mark_set("insert", "end-1c")
1009 if self.reading:
1010 self.text.insert("insert", "\n")
1011 self.text.see("insert")
1012 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001013 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001014 self.text.tag_add("stdin", "iomark", "end-1c")
1015 self.text.update_idletasks()
1016 if self.reading:
1017 self.top.quit() # Break out of recursive mainloop() in raw_input()
1018 else:
1019 self.runit()
1020 return "break"
1021
1022 def recall(self, s):
1023 if self.history:
1024 self.history.recall(s)
1025
1026 def runit(self):
1027 line = self.text.get("iomark", "end-1c")
1028 # Strip off last newline and surrounding whitespace.
1029 # (To allow you to hit return twice to end a statement.)
1030 i = len(line)
1031 while i > 0 and line[i-1] in " \t":
1032 i = i-1
1033 if i > 0 and line[i-1] == "\n":
1034 i = i-1
1035 while i > 0 and line[i-1] in " \t":
1036 i = i-1
1037 line = line[:i]
1038 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001039
David Scherer7aced172000-08-15 01:13:23 +00001040 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001041 if self.interp.rpcclt:
1042 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001043 try:
1044 sys.last_traceback
1045 except:
1046 tkMessageBox.showerror("No stack trace",
1047 "There is no stack trace yet.\n"
1048 "(sys.last_traceback is not defined)",
1049 master=self.text)
1050 return
1051 from StackViewer import StackBrowser
1052 sv = StackBrowser(self.root, self.flist)
1053
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001054 def view_restart_mark(self, event=None):
1055 self.text.see("iomark")
1056 self.text.see("restart")
1057
1058 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001059 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001060
David Scherer7aced172000-08-15 01:13:23 +00001061 def showprompt(self):
1062 self.resetoutput()
1063 try:
1064 s = str(sys.ps1)
1065 except:
1066 s = ""
1067 self.console.write(s)
1068 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001069 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001070 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001071
1072 def resetoutput(self):
1073 source = self.text.get("iomark", "end-1c")
1074 if self.history:
1075 self.history.history_store(source)
1076 if self.text.get("end-2c") != "\n":
1077 self.text.insert("end-1c", "\n")
1078 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001079 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001080 sys.stdout.softspace = 0
1081
1082 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001083 try:
1084 self.text.mark_gravity("iomark", "right")
1085 OutputWindow.write(self, s, tags, "iomark")
1086 self.text.mark_gravity("iomark", "left")
1087 except:
1088 pass
David Scherer7aced172000-08-15 01:13:23 +00001089 if self.canceled:
1090 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001091 if not use_subprocess:
1092 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001093
1094class PseudoFile:
1095
1096 def __init__(self, shell, tags):
1097 self.shell = shell
1098 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001099 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001100
1101 def write(self, s):
1102 self.shell.write(s, self.tags)
1103
1104 def writelines(self, l):
1105 map(self.write, l)
1106
1107 def flush(self):
1108 pass
1109
1110 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001111 return True
David Scherer7aced172000-08-15 01:13:23 +00001112
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001113
David Scherer7aced172000-08-15 01:13:23 +00001114usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001115
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001116USAGE: idle [-deins] [-t title] [file]*
1117 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1118 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001119
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001120 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001121 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001122
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001123The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001124
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001125 -e open an edit window
1126 -i open a shell window
1127
1128The following options imply -i and will open a shell:
1129
1130 -c cmd run the command in a shell, or
1131 -r file run script from file
1132
1133 -d enable the debugger
1134 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1135 -t title set title of shell window
1136
1137A default edit window will be bypassed when -c, -r, or - are used.
1138
1139[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1140
1141Examples:
1142
1143idle
1144 Open an edit window or shell depending on IDLE's configuration.
1145
1146idle foo.py foobar.py
1147 Edit the files, also open a shell if configured to start with shell.
1148
1149idle -est "Baz" foo.py
1150 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1151 window with the title "Baz".
1152
1153idle -c "import sys; print sys.argv" "foo"
1154 Open a shell window and run the command, passing "-c" in sys.argv[0]
1155 and "foo" in sys.argv[1].
1156
1157idle -d -s -r foo.py "Hello World"
1158 Open a shell window, run a startup script, enable the debugger, and
1159 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1160 sys.argv[1].
1161
1162echo "import sys; print sys.argv" | idle - "foobar"
1163 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1164 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001165"""
1166
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001167def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001168 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001169
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001170 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001171 enable_shell = False
1172 enable_edit = False
1173 debug = False
1174 cmd = None
1175 script = None
1176 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001177 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001178 sys.ps1
1179 except AttributeError:
1180 sys.ps1 = '>>> '
1181 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001182 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001183 except getopt.error, msg:
1184 sys.stderr.write("Error: %s\n" % str(msg))
1185 sys.stderr.write(usage_msg)
1186 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001187 for o, a in opts:
1188 if o == '-c':
1189 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001190 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001191 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001192 debug = True
1193 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001194 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001195 enable_edit = True
1196 if o == '-h':
1197 sys.stdout.write(usage_msg)
1198 sys.exit()
1199 if o == '-i':
1200 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001201 if o == '-n':
1202 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001203 if o == '-r':
1204 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001205 if os.path.isfile(script):
1206 pass
1207 else:
1208 print "No script file: ", script
1209 sys.exit()
1210 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001211 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001212 startup = True
1213 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001214 if o == '-t':
1215 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001216 enable_shell = True
1217 if args and args[0] == '-':
1218 cmd = sys.stdin.read()
1219 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001220 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001221 for i in range(len(sys.path)):
1222 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001223 if args and args[0] == '-':
1224 sys.argv = [''] + args[1:]
1225 elif cmd:
1226 sys.argv = ['-c'] + args
1227 elif script:
1228 sys.argv = [script] + args
1229 elif args:
1230 enable_edit = True
1231 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001232 for filename in args:
1233 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001234 for dir in pathx:
1235 dir = os.path.abspath(dir)
1236 if not dir in sys.path:
1237 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001238 else:
1239 dir = os.getcwd()
1240 if not dir in sys.path:
1241 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001242 # check the IDLE settings configuration (but command line overrides)
1243 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001244 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001245 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001246 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001247 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001248 root = Tk(className="Idle")
1249 fixwordbreaks(root)
1250 root.withdraw()
1251 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001252 if enable_edit:
1253 if not (cmd or script):
1254 for filename in args:
1255 flist.open(filename)
1256 if not args:
1257 flist.new()
1258 if enable_shell:
1259 flist.open_shell()
1260 elif enable_shell:
1261 flist.pyshell = PyShell(flist)
1262 flist.pyshell.begin()
1263 shell = flist.pyshell
1264 # handle remaining options:
1265 if debug:
1266 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001267 if startup:
1268 filename = os.environ.get("IDLESTARTUP") or \
1269 os.environ.get("PYTHONSTARTUP")
1270 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001271 shell.interp.execfile(filename)
1272 if cmd or script:
1273 shell.interp.runcommand("""if 1:
1274 import sys as _sys
1275 _sys.argv = %s
1276 del _sys
1277 \n""" % `sys.argv`)
1278 if cmd:
1279 shell.interp.execsource(cmd)
1280 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001281 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001282 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001283 root.mainloop()
1284 root.destroy()
1285
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001286
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001287def display_port_binding_error():
1288 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001289\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001290
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001291IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1292its Python execution server. IDLE is unable to bind to this port, and so
1293cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001294
1295 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001296 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001297 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001298
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001299Run IDLE with the -n command line switch to start without a subprocess
1300and refer to Help/IDLE Help "Running without a subprocess" for further
1301details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001302"""
David Scherer7aced172000-08-15 01:13:23 +00001303
1304if __name__ == "__main__":
1305 main()