blob: f90d31f264222aaa9ff4dc37b7f3f706e599b209 [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
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000314 self.restarting = False
David Scherer7aced172000-08-15 01:13:23 +0000315
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000316 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000317 rpcclt = None
318 rpcpid = None
319
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000320 def spawn_subprocess(self):
Tony Lowndsf53dec22002-12-20 04:24:43 +0000321 args = self.build_subprocess_arglist()
Chui Tey5d2af632002-05-26 13:36:41 +0000322 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000323
Tony Lowndsf53dec22002-12-20 04:24:43 +0000324 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000325 w = ['-W' + s for s in sys.warnoptions]
326 # Maybe IDLE is installed and is being accessed via sys.path,
327 # or maybe it's not installed and the idle.py script is being
328 # run from the IDLE source directory.
329 if __name__ == 'idlelib.PyShell':
330 command = "__import__('idlelib.run').run.main()"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000331 else:
Tony Lownds2398d572003-05-13 15:28:21 +0000332 command = "__import__('run').main()"
333 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000334
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000335 def start_subprocess(self):
336 addr = ("localhost", self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000337 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000338 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000339 time.sleep(i)
340 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000341 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000342 break
343 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000344 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000345 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000346 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000347 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000348 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000349 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000350 # Accept the connection from the Python execution server
351 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000352 self.rpcclt.register("stdin", self.tkconsole)
353 self.rpcclt.register("stdout", self.tkconsole.stdout)
354 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000355 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000356 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000357 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000358 self.poll_subprocess()
359
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000360 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000361 if self.restarting:
362 return
363 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000364 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000365 debug = self.getdebugger()
366 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000367 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000368 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000369 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
370 except:
371 pass
372 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000373 self.rpcclt.close()
374 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000375 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000376 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000377 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000378 self.spawn_subprocess()
379 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000380 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000381 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000382 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000383 if was_executing:
384 console.write('\n')
385 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000386 halfbar = ((int(console.width) - 16) // 2) * '='
387 console.write(halfbar + ' RESTART ' + halfbar)
388 console.text.mark_set("restart", "end-1c")
389 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000390 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000391 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000392 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000393 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000394 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000395 # reload remote debugger breakpoints for all PyShellEditWindows
396 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000397 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000398
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000399 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000400 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000401
402 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000403 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000404
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000405 def kill_subprocess(self):
406 self.rpcclt.close()
407 self.unix_terminate()
408 self.tkconsole.executing = False
409 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000410
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000411 def unix_terminate(self):
412 "UNIX: make sure subprocess is terminated and collect status"
413 if hasattr(os, 'kill'):
414 try:
415 os.kill(self.rpcpid, SIGTERM)
416 except OSError:
417 # process already terminated:
418 return
419 else:
420 try:
421 os.waitpid(self.rpcpid, 0)
422 except OSError:
423 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000424
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000425 def transfer_path(self):
426 self.runcommand("""if 1:
427 import sys as _sys
428 _sys.path = %s
429 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000430 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
431 __builtins__.quit = __builtins__.exit = _msg
432 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000433 \n""" % `sys.path`)
434
Chui Tey5d2af632002-05-26 13:36:41 +0000435 active_seq = None
436
437 def poll_subprocess(self):
438 clt = self.rpcclt
439 if clt is None:
440 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000441 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000442 response = clt.pollresponse(self.active_seq, wait=0.05)
443 except (EOFError, IOError, KeyboardInterrupt):
444 # lost connection or subprocess terminated itself, restart
445 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000446 if self.tkconsole.closing:
447 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000448 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000449 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000450 if response:
451 self.tkconsole.resetoutput()
452 self.active_seq = None
453 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000454 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000455 if how == "OK":
456 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000457 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000458 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000459 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
460 self.remote_stack_viewer()
461 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000462 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
463 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000464 print >>console, errmsg, what
465 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000466 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000467 # Reschedule myself
468 if not self.tkconsole.closing:
469 self.tkconsole.text.after(self.tkconsole.pollinterval,
470 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000471
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000472 debugger = None
473
474 def setdebugger(self, debugger):
475 self.debugger = debugger
476
477 def getdebugger(self):
478 return self.debugger
479
Chui Tey5d2af632002-05-26 13:36:41 +0000480 def remote_stack_viewer(self):
481 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000482 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000483 if oid is None:
484 self.tkconsole.root.bell()
485 return
486 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
487 from TreeWidget import ScrolledCanvas, TreeNode
488 top = Toplevel(self.tkconsole.root)
489 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
490 sc.frame.pack(expand=1, fill="both")
491 node = TreeNode(sc.canvas, None, item)
492 node.expand()
493 # XXX Should GC the remote tree when closing the window
494
David Scherer7aced172000-08-15 01:13:23 +0000495 gid = 0
496
497 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000498 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000499 filename = self.stuffsource(source)
500 self.execfile(filename, source)
501
502 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000503 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000504 if source is None:
505 source = open(filename, "r").read()
506 try:
507 code = compile(source, filename, "exec")
508 except (OverflowError, SyntaxError):
509 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000510 tkerr = self.tkconsole.stderr
511 print>>tkerr, '*** Error in script or command!\n'
512 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000513 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000514 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000515 else:
516 self.runcode(code)
517
518 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000519 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000520 filename = self.stuffsource(source)
521 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000522 self.save_warnings_filters = warnings.filters[:]
523 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000524 if isinstance(source, types.UnicodeType):
525 import IOBinding
526 try:
527 source = source.encode(IOBinding.encoding)
528 except UnicodeError:
529 self.tkconsole.resetoutput()
530 self.write("Unsupported characters in input")
531 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000532 try:
533 return InteractiveInterpreter.runsource(self, source, filename)
534 finally:
535 if self.save_warnings_filters is not None:
536 warnings.filters[:] = self.save_warnings_filters
537 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000538
539 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000540 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000541 filename = "<pyshell#%d>" % self.gid
542 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000543 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000544 linecache.cache[filename] = len(source)+1, 0, lines, filename
545 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000546
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000547 def prepend_syspath(self, filename):
548 "Prepend sys.path with file's directory if not already included"
549 self.runcommand("""if 1:
550 _filename = %s
551 import sys as _sys
552 from os.path import dirname as _dirname
553 _dir = _dirname(_filename)
554 if not _dir in _sys.path:
555 _sys.path.insert(0, _dir)
556 del _filename, _sys, _dirname, _dir
557 \n""" % `filename`)
558
David Scherer7aced172000-08-15 01:13:23 +0000559 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000560 """Extend base class method: Add Colorizing
561
562 Color the offending position instead of printing it and pointing at it
563 with a caret.
564
565 """
David Scherer7aced172000-08-15 01:13:23 +0000566 text = self.tkconsole.text
567 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000568 if stuff:
569 msg, lineno, offset, line = stuff
570 if lineno == 1:
571 pos = "iomark + %d chars" % (offset-1)
572 else:
573 pos = "iomark linestart + %d lines + %d chars" % \
574 (lineno-1, offset-1)
575 text.tag_add("ERROR", pos)
576 text.see(pos)
577 char = text.get(pos)
578 if char and char in IDENTCHARS:
579 text.tag_add("ERROR", pos + " wordstart", pos)
580 self.tkconsole.resetoutput()
581 self.write("SyntaxError: %s\n" % str(msg))
582 else:
David Scherer7aced172000-08-15 01:13:23 +0000583 self.tkconsole.resetoutput()
584 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000585 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000586
587 def unpackerror(self):
588 type, value, tb = sys.exc_info()
589 ok = type is SyntaxError
590 if ok:
591 try:
592 msg, (dummy_filename, lineno, offset, line) = value
593 except:
594 ok = 0
595 if ok:
596 return msg, lineno, offset, line
597 else:
598 return None
599
600 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000601 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000602 self.tkconsole.resetoutput()
603 self.checklinecache()
604 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000605 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
606 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000607
608 def checklinecache(self):
609 c = linecache.cache
610 for key in c.keys():
611 if key[:1] + key[-1:] != "<>":
612 del c[key]
613
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000614 def display_executing_dialog(self):
615 tkMessageBox.showerror(
616 "Already executing",
617 "The Python Shell window is already executing a command; "
618 "please wait until it is finished.",
619 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000620
Chui Tey5d2af632002-05-26 13:36:41 +0000621 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000622 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000623 # The code better not raise an exception!
624 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000625 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000626 return 0
627 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000628 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000629 else:
630 exec code in self.locals
631 return 1
632
David Scherer7aced172000-08-15 01:13:23 +0000633 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000634 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000635 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000636 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000637 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000638 if self.save_warnings_filters is not None:
639 warnings.filters[:] = self.save_warnings_filters
640 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000641 debugger = self.debugger
642 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000643 self.tkconsole.beginexecuting()
644 try:
645 if not debugger and self.rpcclt is not None:
646 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
647 (code,), {})
648 elif debugger:
649 debugger.run(code, self.locals)
650 else:
651 exec code in self.locals
652 except SystemExit:
653 if tkMessageBox.askyesno(
654 "Exit?",
655 "Do you want to exit altogether?",
656 default="yes",
657 master=self.tkconsole.text):
658 raise
659 else:
660 self.showtraceback()
661 except:
David Scherer7aced172000-08-15 01:13:23 +0000662 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000663 finally:
664 if not use_subprocess:
665 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000666
667 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000668 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000669 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000670
David Scherer7aced172000-08-15 01:13:23 +0000671class PyShell(OutputWindow):
672
673 shell_title = "Python Shell"
674
675 # Override classes
676 ColorDelegator = ModifiedColorDelegator
677 UndoDelegator = ModifiedUndoDelegator
678
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000679 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000680 menu_specs = [
681 ("file", "_File"),
682 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000683 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000684 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000685 ("windows", "_Windows"),
686 ("help", "_Help"),
687 ]
David Scherer7aced172000-08-15 01:13:23 +0000688
689 # New classes
690 from IdleHistory import History
691
692 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000693 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000694 ms = self.menu_specs
695 if ms[2][0] != "shell":
696 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000697 self.interp = ModifiedInterpreter(self)
698 if flist is None:
699 root = Tk()
700 fixwordbreaks(root)
701 root.withdraw()
702 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000703 #
David Scherer7aced172000-08-15 01:13:23 +0000704 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000705 #
David Scherer7aced172000-08-15 01:13:23 +0000706 import __builtin__
707 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000708 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000709 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000710 #
David Scherer7aced172000-08-15 01:13:23 +0000711 text = self.text
712 text.configure(wrap="char")
713 text.bind("<<newline-and-indent>>", self.enter_callback)
714 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
715 text.bind("<<interrupt-execution>>", self.cancel_callback)
716 text.bind("<<beginning-of-line>>", self.home_callback)
717 text.bind("<<end-of-file>>", self.eof_callback)
718 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000719 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000720 text.bind("<<open-python-shell>>", self.flist.open_shell)
721 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000722 if use_subprocess:
723 text.bind("<<view-restart>>", self.view_restart_mark)
724 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000725 #
David Scherer7aced172000-08-15 01:13:23 +0000726 self.save_stdout = sys.stdout
727 self.save_stderr = sys.stderr
728 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000729 self.stdout = PseudoFile(self, "stdout")
730 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000731 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000732 if not use_subprocess:
733 sys.stdout = self.stdout
734 sys.stderr = self.stderr
735 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000736 #
David Scherer7aced172000-08-15 01:13:23 +0000737 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000738 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000739 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000740 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000741 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000742
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000743 reading = False
744 executing = False
745 canceled = False
746 endoffile = False
747 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000748
749 def toggle_debugger(self, event=None):
750 if self.executing:
751 tkMessageBox.showerror("Don't debug now",
752 "You can only toggle the debugger when idle",
753 master=self.text)
754 self.set_debugger_indicator()
755 return "break"
756 else:
757 db = self.interp.getdebugger()
758 if db:
759 self.close_debugger()
760 else:
761 self.open_debugger()
762
763 def set_debugger_indicator(self):
764 db = self.interp.getdebugger()
765 self.setvar("<<toggle-debugger>>", not not db)
766
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000767 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000768 pass # All we need is the variable
769
770 def close_debugger(self):
771 db = self.interp.getdebugger()
772 if db:
773 self.interp.setdebugger(None)
774 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000775 if self.interp.rpcclt:
776 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000777 self.resetoutput()
778 self.console.write("[DEBUG OFF]\n")
779 sys.ps1 = ">>> "
780 self.showprompt()
781 self.set_debugger_indicator()
782
783 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000784 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000785 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
786 self)
787 else:
788 dbg_gui = Debugger.Debugger(self)
789 self.interp.setdebugger(dbg_gui)
790 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000791 sys.ps1 = "[DEBUG ON]\n>>> "
792 self.showprompt()
793 self.set_debugger_indicator()
794
David Scherer7aced172000-08-15 01:13:23 +0000795 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000796 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000797 self.resetoutput()
798 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000799
800 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000801 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000802 self.executing = 0
803 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000804 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000805
806 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000807 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000808 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000809 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000810 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000811 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000812 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000813 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000814 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000815 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000816 self.closing = True
817 # Wait for poll_subprocess() rescheduling to stop
818 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000819
820 def close2(self):
821 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000822
823 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000824 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000825 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000826 if use_subprocess:
827 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000828 # Restore std streams
829 sys.stdout = self.save_stdout
830 sys.stderr = self.save_stderr
831 sys.stdin = self.save_stdin
832 # Break cycles
833 self.interp = None
834 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000835 self.flist.pyshell = None
836 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000837 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000838
839 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000840 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000841 return True
David Scherer7aced172000-08-15 01:13:23 +0000842
843 def short_title(self):
844 return self.shell_title
845
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000846 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000847 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000848
David Scherer7aced172000-08-15 01:13:23 +0000849 def begin(self):
850 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000851 if use_subprocess:
852 nosub = ''
853 else:
854 nosub = "==== No Subprocess ===="
855 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000856 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000857 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000858 self.showprompt()
859 import Tkinter
860 Tkinter._default_root = None
861
862 def interact(self):
863 self.begin()
864 self.top.mainloop()
865
866 def readline(self):
867 save = self.reading
868 try:
869 self.reading = 1
870 self.top.mainloop()
871 finally:
872 self.reading = save
873 line = self.text.get("iomark", "end-1c")
874 self.resetoutput()
875 if self.canceled:
876 self.canceled = 0
877 raise KeyboardInterrupt
878 if self.endoffile:
879 self.endoffile = 0
880 return ""
881 return line
882
883 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000884 return True
David Scherer7aced172000-08-15 01:13:23 +0000885
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000886 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000887 try:
888 if self.text.compare("sel.first", "!=", "sel.last"):
889 return # Active selection -- always use default binding
890 except:
891 pass
892 if not (self.executing or self.reading):
893 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000894 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000895 self.showprompt()
896 return "break"
897 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000898 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000899 if self.reading:
900 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000901 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000902 if self.interp.getdebugger():
903 self.interp.restart_subprocess()
904 else:
905 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000906 return "break"
907
908 def eof_callback(self, event):
909 if self.executing and not self.reading:
910 return # Let the default binding (delete next char) take over
911 if not (self.text.compare("iomark", "==", "insert") and
912 self.text.compare("insert", "==", "end-1c")):
913 return # Let the default binding (delete next char) take over
914 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000915 self.resetoutput()
916 self.close()
917 else:
918 self.canceled = 0
919 self.endoffile = 1
920 self.top.quit()
921 return "break"
922
923 def home_callback(self, event):
924 if event.state != 0 and event.keysym == "Home":
925 return # <Modifier-Home>; fall back to class binding
926 if self.text.compare("iomark", "<=", "insert") and \
927 self.text.compare("insert linestart", "<=", "iomark"):
928 self.text.mark_set("insert", "iomark")
929 self.text.tag_remove("sel", "1.0", "end")
930 self.text.see("insert")
931 return "break"
932
933 def linefeed_callback(self, event):
934 # Insert a linefeed without entering anything (still autoindented)
935 if self.reading:
936 self.text.insert("insert", "\n")
937 self.text.see("insert")
938 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000939 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000940 return "break"
941
942 def enter_callback(self, event):
943 if self.executing and not self.reading:
944 return # Let the default binding (insert '\n') take over
945 # If some text is selected, recall the selection
946 # (but only if this before the I/O mark)
947 try:
948 sel = self.text.get("sel.first", "sel.last")
949 if sel:
950 if self.text.compare("sel.last", "<=", "iomark"):
951 self.recall(sel)
952 return "break"
953 except:
954 pass
955 # If we're strictly before the line containing iomark, recall
956 # the current line, less a leading prompt, less leading or
957 # trailing whitespace
958 if self.text.compare("insert", "<", "iomark linestart"):
959 # Check if there's a relevant stdin range -- if so, use it
960 prev = self.text.tag_prevrange("stdin", "insert")
961 if prev and self.text.compare("insert", "<", prev[1]):
962 self.recall(self.text.get(prev[0], prev[1]))
963 return "break"
964 next = self.text.tag_nextrange("stdin", "insert")
965 if next and self.text.compare("insert lineend", ">=", next[0]):
966 self.recall(self.text.get(next[0], next[1]))
967 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000968 # No stdin mark -- just get the current line, less any prompt
969 line = self.text.get("insert linestart", "insert lineend")
970 last_line_of_prompt = sys.ps1.split('\n')[-1]
971 if line.startswith(last_line_of_prompt):
972 line = line[len(last_line_of_prompt):]
973 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000974 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000975 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000976 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000977 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000978 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000979 # If we're in the current input and there's only whitespace
980 # beyond the cursor, erase that whitespace first
981 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000982 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000983 self.text.delete("insert", "end-1c")
984 # If we're in the current input before its last line,
985 # insert a newline right at the insert point
986 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000987 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000988 return "break"
989 # We're in the last line; append a newline and submit it
990 self.text.mark_set("insert", "end-1c")
991 if self.reading:
992 self.text.insert("insert", "\n")
993 self.text.see("insert")
994 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000995 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000996 self.text.tag_add("stdin", "iomark", "end-1c")
997 self.text.update_idletasks()
998 if self.reading:
999 self.top.quit() # Break out of recursive mainloop() in raw_input()
1000 else:
1001 self.runit()
1002 return "break"
1003
1004 def recall(self, s):
1005 if self.history:
1006 self.history.recall(s)
1007
1008 def runit(self):
1009 line = self.text.get("iomark", "end-1c")
1010 # Strip off last newline and surrounding whitespace.
1011 # (To allow you to hit return twice to end a statement.)
1012 i = len(line)
1013 while i > 0 and line[i-1] in " \t":
1014 i = i-1
1015 if i > 0 and line[i-1] == "\n":
1016 i = i-1
1017 while i > 0 and line[i-1] in " \t":
1018 i = i-1
1019 line = line[:i]
1020 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001021
David Scherer7aced172000-08-15 01:13:23 +00001022 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001023 if self.interp.rpcclt:
1024 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001025 try:
1026 sys.last_traceback
1027 except:
1028 tkMessageBox.showerror("No stack trace",
1029 "There is no stack trace yet.\n"
1030 "(sys.last_traceback is not defined)",
1031 master=self.text)
1032 return
1033 from StackViewer import StackBrowser
1034 sv = StackBrowser(self.root, self.flist)
1035
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001036 def view_restart_mark(self, event=None):
1037 self.text.see("iomark")
1038 self.text.see("restart")
1039
1040 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001041 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001042
David Scherer7aced172000-08-15 01:13:23 +00001043 def showprompt(self):
1044 self.resetoutput()
1045 try:
1046 s = str(sys.ps1)
1047 except:
1048 s = ""
1049 self.console.write(s)
1050 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001051 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001052 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001053
1054 def resetoutput(self):
1055 source = self.text.get("iomark", "end-1c")
1056 if self.history:
1057 self.history.history_store(source)
1058 if self.text.get("end-2c") != "\n":
1059 self.text.insert("end-1c", "\n")
1060 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001061 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001062 sys.stdout.softspace = 0
1063
1064 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001065 try:
1066 self.text.mark_gravity("iomark", "right")
1067 OutputWindow.write(self, s, tags, "iomark")
1068 self.text.mark_gravity("iomark", "left")
1069 except:
1070 pass
David Scherer7aced172000-08-15 01:13:23 +00001071 if self.canceled:
1072 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001073 if not use_subprocess:
1074 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001075
1076class PseudoFile:
1077
1078 def __init__(self, shell, tags):
1079 self.shell = shell
1080 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001081 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001082
1083 def write(self, s):
1084 self.shell.write(s, self.tags)
1085
1086 def writelines(self, l):
1087 map(self.write, l)
1088
1089 def flush(self):
1090 pass
1091
1092 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001093 return True
David Scherer7aced172000-08-15 01:13:23 +00001094
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001095
David Scherer7aced172000-08-15 01:13:23 +00001096usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001097
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001098USAGE: idle [-deins] [-t title] [file]*
1099 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1100 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001101
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001102 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001103 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001104
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001105The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001106
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001107 -e open an edit window
1108 -i open a shell window
1109
1110The following options imply -i and will open a shell:
1111
1112 -c cmd run the command in a shell, or
1113 -r file run script from file
1114
1115 -d enable the debugger
1116 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1117 -t title set title of shell window
1118
1119A default edit window will be bypassed when -c, -r, or - are used.
1120
1121[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1122
1123Examples:
1124
1125idle
1126 Open an edit window or shell depending on IDLE's configuration.
1127
1128idle foo.py foobar.py
1129 Edit the files, also open a shell if configured to start with shell.
1130
1131idle -est "Baz" foo.py
1132 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1133 window with the title "Baz".
1134
1135idle -c "import sys; print sys.argv" "foo"
1136 Open a shell window and run the command, passing "-c" in sys.argv[0]
1137 and "foo" in sys.argv[1].
1138
1139idle -d -s -r foo.py "Hello World"
1140 Open a shell window, run a startup script, enable the debugger, and
1141 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1142 sys.argv[1].
1143
1144echo "import sys; print sys.argv" | idle - "foobar"
1145 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1146 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001147"""
1148
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001149def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001150 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001151
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001152 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001153 enable_shell = False
1154 enable_edit = False
1155 debug = False
1156 cmd = None
1157 script = None
1158 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001159 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001160 sys.ps1
1161 except AttributeError:
1162 sys.ps1 = '>>> '
1163 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001164 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001165 except getopt.error, msg:
1166 sys.stderr.write("Error: %s\n" % str(msg))
1167 sys.stderr.write(usage_msg)
1168 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001169 for o, a in opts:
1170 if o == '-c':
1171 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001172 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001173 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001174 debug = True
1175 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001176 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001177 enable_edit = True
1178 if o == '-h':
1179 sys.stdout.write(usage_msg)
1180 sys.exit()
1181 if o == '-i':
1182 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001183 if o == '-n':
1184 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001185 if o == '-r':
1186 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001187 if os.path.isfile(script):
1188 pass
1189 else:
1190 print "No script file: ", script
1191 sys.exit()
1192 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001193 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001194 startup = True
1195 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001196 if o == '-t':
1197 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001198 enable_shell = True
1199 if args and args[0] == '-':
1200 cmd = sys.stdin.read()
1201 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001202 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001203 for i in range(len(sys.path)):
1204 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001205 if args and args[0] == '-':
1206 sys.argv = [''] + args[1:]
1207 elif cmd:
1208 sys.argv = ['-c'] + args
1209 elif script:
1210 sys.argv = [script] + args
1211 elif args:
1212 enable_edit = True
1213 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001214 for filename in args:
1215 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001216 for dir in pathx:
1217 dir = os.path.abspath(dir)
1218 if not dir in sys.path:
1219 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001220 else:
1221 dir = os.getcwd()
1222 if not dir in sys.path:
1223 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001224 # check the IDLE settings configuration (but command line overrides)
1225 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001226 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001227 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001228 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001229 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001230 root = Tk(className="Idle")
1231 fixwordbreaks(root)
1232 root.withdraw()
1233 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001234 if enable_edit:
1235 if not (cmd or script):
1236 for filename in args:
1237 flist.open(filename)
1238 if not args:
1239 flist.new()
1240 if enable_shell:
1241 flist.open_shell()
1242 elif enable_shell:
1243 flist.pyshell = PyShell(flist)
1244 flist.pyshell.begin()
1245 shell = flist.pyshell
1246 # handle remaining options:
1247 if debug:
1248 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001249 if startup:
1250 filename = os.environ.get("IDLESTARTUP") or \
1251 os.environ.get("PYTHONSTARTUP")
1252 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001253 shell.interp.execfile(filename)
1254 if cmd or script:
1255 shell.interp.runcommand("""if 1:
1256 import sys as _sys
1257 _sys.argv = %s
1258 del _sys
1259 \n""" % `sys.argv`)
1260 if cmd:
1261 shell.interp.execsource(cmd)
1262 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001263 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001264 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001265 root.mainloop()
1266 root.destroy()
1267
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001268
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001269def display_port_binding_error():
1270 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001271\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001272
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001273IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1274its Python execution server. IDLE is unable to bind to this port, and so
1275cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001276
1277 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001278 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001279 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001280
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001281Run IDLE with the -n command line switch to start without a subprocess
1282and refer to Help/IDLE Help "Running without a subprocess" for further
1283details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001284"""
David Scherer7aced172000-08-15 01:13:23 +00001285
1286if __name__ == "__main__":
1287 main()