blob: db4a05b38ee38aa6a082233dd292fc3eb4542982 [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
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000306
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
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000315 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000316
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000317 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000318 rpcclt = None
319 rpcpid = None
320
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000321 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000322 args = self.subprocess_arglist
Chui Tey5d2af632002-05-26 13:36:41 +0000323 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000324
Tony Lowndsf53dec22002-12-20 04:24:43 +0000325 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000326 w = ['-W' + s for s in sys.warnoptions]
327 # Maybe IDLE is installed and is being accessed via sys.path,
328 # or maybe it's not installed and the idle.py script is being
329 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000330 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
331 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000332 if __name__ == 'idlelib.PyShell':
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000333 command = "__import__('idlelib.run').run.main(" + `del_exitf` +")"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000334 else:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000335 command = "__import__('run').main(" + `del_exitf` + ")"
Tony Lownds2398d572003-05-13 15:28:21 +0000336 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000337
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000338 def start_subprocess(self):
339 addr = ("localhost", self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000340 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000341 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000342 time.sleep(i)
343 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000344 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000345 break
346 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000347 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000348 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000349 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000350 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000351 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000352 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000353 # Accept the connection from the Python execution server
354 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000355 self.rpcclt.register("stdin", self.tkconsole)
356 self.rpcclt.register("stdout", self.tkconsole.stdout)
357 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000358 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000359 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000360 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000361 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000362 self.poll_subprocess()
363
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000364 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000365 if self.restarting:
366 return
367 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000368 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000369 debug = self.getdebugger()
370 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000371 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000372 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000373 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
374 except:
375 pass
376 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000377 self.rpcclt.close()
378 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000379 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000380 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000381 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000382 self.spawn_subprocess()
383 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000384 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000385 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000386 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000387 if was_executing:
388 console.write('\n')
389 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000390 halfbar = ((int(console.width) - 16) // 2) * '='
391 console.write(halfbar + ' RESTART ' + halfbar)
392 console.text.mark_set("restart", "end-1c")
393 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000394 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000395 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000396 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000397 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000398 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000399 # reload remote debugger breakpoints for all PyShellEditWindows
400 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000401 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000402
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000403 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000404 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000405
406 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000407 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000408
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000409 def kill_subprocess(self):
410 self.rpcclt.close()
411 self.unix_terminate()
412 self.tkconsole.executing = False
413 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000414
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000415 def unix_terminate(self):
416 "UNIX: make sure subprocess is terminated and collect status"
417 if hasattr(os, 'kill'):
418 try:
419 os.kill(self.rpcpid, SIGTERM)
420 except OSError:
421 # process already terminated:
422 return
423 else:
424 try:
425 os.waitpid(self.rpcpid, 0)
426 except OSError:
427 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000428
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000429 def transfer_path(self):
430 self.runcommand("""if 1:
431 import sys as _sys
432 _sys.path = %s
433 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000434 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
435 __builtins__.quit = __builtins__.exit = _msg
436 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000437 \n""" % `sys.path`)
438
Chui Tey5d2af632002-05-26 13:36:41 +0000439 active_seq = None
440
441 def poll_subprocess(self):
442 clt = self.rpcclt
443 if clt is None:
444 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000445 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000446 response = clt.pollresponse(self.active_seq, wait=0.05)
447 except (EOFError, IOError, KeyboardInterrupt):
448 # lost connection or subprocess terminated itself, restart
449 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000450 if self.tkconsole.closing:
451 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000453 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000454 if response:
455 self.tkconsole.resetoutput()
456 self.active_seq = None
457 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000458 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000459 if how == "OK":
460 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000461 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000462 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000463 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
464 self.remote_stack_viewer()
465 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000466 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
467 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000468 print >>console, errmsg, what
469 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000470 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000471 # Reschedule myself
472 if not self.tkconsole.closing:
473 self.tkconsole.text.after(self.tkconsole.pollinterval,
474 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000475
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000476 debugger = None
477
478 def setdebugger(self, debugger):
479 self.debugger = debugger
480
481 def getdebugger(self):
482 return self.debugger
483
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000484 def open_remote_stack_viewer(self):
485 """Initiate the remote stack viewer from a separate thread.
486
487 This method is called from the subprocess, and by returning from this
488 method we allow the subprocess to unblock. After a bit the shell
489 requests the subprocess to open the remote stack viewer which returns a
490 static object looking at the last exceptiopn. It is queried through
491 the RPC mechanism.
492
493 """
494 self.tkconsole.text.after(300, self.remote_stack_viewer)
495 return
496
Chui Tey5d2af632002-05-26 13:36:41 +0000497 def remote_stack_viewer(self):
498 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000499 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000500 if oid is None:
501 self.tkconsole.root.bell()
502 return
503 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
504 from TreeWidget import ScrolledCanvas, TreeNode
505 top = Toplevel(self.tkconsole.root)
506 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
507 sc.frame.pack(expand=1, fill="both")
508 node = TreeNode(sc.canvas, None, item)
509 node.expand()
510 # XXX Should GC the remote tree when closing the window
511
David Scherer7aced172000-08-15 01:13:23 +0000512 gid = 0
513
514 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000515 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000516 filename = self.stuffsource(source)
517 self.execfile(filename, source)
518
519 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000520 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000521 if source is None:
522 source = open(filename, "r").read()
523 try:
524 code = compile(source, filename, "exec")
525 except (OverflowError, SyntaxError):
526 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000527 tkerr = self.tkconsole.stderr
528 print>>tkerr, '*** Error in script or command!\n'
529 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000530 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000531 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000532 else:
533 self.runcode(code)
534
535 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000536 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000537 filename = self.stuffsource(source)
538 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000539 self.save_warnings_filters = warnings.filters[:]
540 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000541 if isinstance(source, types.UnicodeType):
542 import IOBinding
543 try:
544 source = source.encode(IOBinding.encoding)
545 except UnicodeError:
546 self.tkconsole.resetoutput()
547 self.write("Unsupported characters in input")
548 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000549 try:
550 return InteractiveInterpreter.runsource(self, source, filename)
551 finally:
552 if self.save_warnings_filters is not None:
553 warnings.filters[:] = self.save_warnings_filters
554 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000555
556 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000557 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000558 filename = "<pyshell#%d>" % self.gid
559 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000560 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000561 linecache.cache[filename] = len(source)+1, 0, lines, filename
562 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000563
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000564 def prepend_syspath(self, filename):
565 "Prepend sys.path with file's directory if not already included"
566 self.runcommand("""if 1:
567 _filename = %s
568 import sys as _sys
569 from os.path import dirname as _dirname
570 _dir = _dirname(_filename)
571 if not _dir in _sys.path:
572 _sys.path.insert(0, _dir)
573 del _filename, _sys, _dirname, _dir
574 \n""" % `filename`)
575
David Scherer7aced172000-08-15 01:13:23 +0000576 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000577 """Extend base class method: Add Colorizing
578
579 Color the offending position instead of printing it and pointing at it
580 with a caret.
581
582 """
David Scherer7aced172000-08-15 01:13:23 +0000583 text = self.tkconsole.text
584 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000585 if stuff:
586 msg, lineno, offset, line = stuff
587 if lineno == 1:
588 pos = "iomark + %d chars" % (offset-1)
589 else:
590 pos = "iomark linestart + %d lines + %d chars" % \
591 (lineno-1, offset-1)
592 text.tag_add("ERROR", pos)
593 text.see(pos)
594 char = text.get(pos)
595 if char and char in IDENTCHARS:
596 text.tag_add("ERROR", pos + " wordstart", pos)
597 self.tkconsole.resetoutput()
598 self.write("SyntaxError: %s\n" % str(msg))
599 else:
David Scherer7aced172000-08-15 01:13:23 +0000600 self.tkconsole.resetoutput()
601 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000602 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000603
604 def unpackerror(self):
605 type, value, tb = sys.exc_info()
606 ok = type is SyntaxError
607 if ok:
608 try:
609 msg, (dummy_filename, lineno, offset, line) = value
610 except:
611 ok = 0
612 if ok:
613 return msg, lineno, offset, line
614 else:
615 return None
616
617 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000618 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000619 self.tkconsole.resetoutput()
620 self.checklinecache()
621 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000622 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
623 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000624
625 def checklinecache(self):
626 c = linecache.cache
627 for key in c.keys():
628 if key[:1] + key[-1:] != "<>":
629 del c[key]
630
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000631 def display_executing_dialog(self):
632 tkMessageBox.showerror(
633 "Already executing",
634 "The Python Shell window is already executing a command; "
635 "please wait until it is finished.",
636 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000637
Chui Tey5d2af632002-05-26 13:36:41 +0000638 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000639 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000640 # The code better not raise an exception!
641 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000642 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000643 return 0
644 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000645 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000646 else:
647 exec code in self.locals
648 return 1
649
David Scherer7aced172000-08-15 01:13:23 +0000650 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000651 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000652 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000653 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000654 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000655 if self.save_warnings_filters is not None:
656 warnings.filters[:] = self.save_warnings_filters
657 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000658 debugger = self.debugger
659 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000660 self.tkconsole.beginexecuting()
661 try:
662 if not debugger and self.rpcclt is not None:
663 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
664 (code,), {})
665 elif debugger:
666 debugger.run(code, self.locals)
667 else:
668 exec code in self.locals
669 except SystemExit:
670 if tkMessageBox.askyesno(
671 "Exit?",
672 "Do you want to exit altogether?",
673 default="yes",
674 master=self.tkconsole.text):
675 raise
676 else:
677 self.showtraceback()
678 except:
David Scherer7aced172000-08-15 01:13:23 +0000679 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000680 finally:
681 if not use_subprocess:
682 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000683
684 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000685 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000686 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000687
David Scherer7aced172000-08-15 01:13:23 +0000688class PyShell(OutputWindow):
689
690 shell_title = "Python Shell"
691
692 # Override classes
693 ColorDelegator = ModifiedColorDelegator
694 UndoDelegator = ModifiedUndoDelegator
695
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000696 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000697 menu_specs = [
698 ("file", "_File"),
699 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000700 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000701 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000702 ("windows", "_Windows"),
703 ("help", "_Help"),
704 ]
David Scherer7aced172000-08-15 01:13:23 +0000705
706 # New classes
707 from IdleHistory import History
708
709 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000710 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000711 ms = self.menu_specs
712 if ms[2][0] != "shell":
713 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000714 self.interp = ModifiedInterpreter(self)
715 if flist is None:
716 root = Tk()
717 fixwordbreaks(root)
718 root.withdraw()
719 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000720 #
David Scherer7aced172000-08-15 01:13:23 +0000721 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000722 #
David Scherer7aced172000-08-15 01:13:23 +0000723 import __builtin__
724 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000725 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000726 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000727 #
David Scherer7aced172000-08-15 01:13:23 +0000728 text = self.text
729 text.configure(wrap="char")
730 text.bind("<<newline-and-indent>>", self.enter_callback)
731 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
732 text.bind("<<interrupt-execution>>", self.cancel_callback)
733 text.bind("<<beginning-of-line>>", self.home_callback)
734 text.bind("<<end-of-file>>", self.eof_callback)
735 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000736 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000737 text.bind("<<open-python-shell>>", self.flist.open_shell)
738 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000739 if use_subprocess:
740 text.bind("<<view-restart>>", self.view_restart_mark)
741 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000742 #
David Scherer7aced172000-08-15 01:13:23 +0000743 self.save_stdout = sys.stdout
744 self.save_stderr = sys.stderr
745 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000746 self.stdout = PseudoFile(self, "stdout")
747 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000748 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000749 if not use_subprocess:
750 sys.stdout = self.stdout
751 sys.stderr = self.stderr
752 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000753 #
David Scherer7aced172000-08-15 01:13:23 +0000754 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000755 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000756 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000757 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000758 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000759
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000760 reading = False
761 executing = False
762 canceled = False
763 endoffile = False
764 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000765
766 def toggle_debugger(self, event=None):
767 if self.executing:
768 tkMessageBox.showerror("Don't debug now",
769 "You can only toggle the debugger when idle",
770 master=self.text)
771 self.set_debugger_indicator()
772 return "break"
773 else:
774 db = self.interp.getdebugger()
775 if db:
776 self.close_debugger()
777 else:
778 self.open_debugger()
779
780 def set_debugger_indicator(self):
781 db = self.interp.getdebugger()
782 self.setvar("<<toggle-debugger>>", not not db)
783
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000784 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000785 pass # All we need is the variable
786
787 def close_debugger(self):
788 db = self.interp.getdebugger()
789 if db:
790 self.interp.setdebugger(None)
791 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000792 if self.interp.rpcclt:
793 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000794 self.resetoutput()
795 self.console.write("[DEBUG OFF]\n")
796 sys.ps1 = ">>> "
797 self.showprompt()
798 self.set_debugger_indicator()
799
800 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000801 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000802 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
803 self)
804 else:
805 dbg_gui = Debugger.Debugger(self)
806 self.interp.setdebugger(dbg_gui)
807 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000808 sys.ps1 = "[DEBUG ON]\n>>> "
809 self.showprompt()
810 self.set_debugger_indicator()
811
David Scherer7aced172000-08-15 01:13:23 +0000812 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000813 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000814 self.resetoutput()
815 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000816
817 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000818 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000819 self.executing = 0
820 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000821 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000822
823 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000824 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000825 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000826 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000827 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000828 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000829 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000830 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000831 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000832 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000833 self.closing = True
834 # Wait for poll_subprocess() rescheduling to stop
835 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000836
837 def close2(self):
838 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000839
840 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000841 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000842 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000843 if use_subprocess:
844 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000845 # Restore std streams
846 sys.stdout = self.save_stdout
847 sys.stderr = self.save_stderr
848 sys.stdin = self.save_stdin
849 # Break cycles
850 self.interp = None
851 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000852 self.flist.pyshell = None
853 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000854 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000855
856 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000857 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000858 return True
David Scherer7aced172000-08-15 01:13:23 +0000859
860 def short_title(self):
861 return self.shell_title
862
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000863 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000864 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000865
David Scherer7aced172000-08-15 01:13:23 +0000866 def begin(self):
867 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000868 if use_subprocess:
869 nosub = ''
870 else:
871 nosub = "==== No Subprocess ===="
872 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000873 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000874 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000875 self.showprompt()
876 import Tkinter
877 Tkinter._default_root = None
878
879 def interact(self):
880 self.begin()
881 self.top.mainloop()
882
883 def readline(self):
884 save = self.reading
885 try:
886 self.reading = 1
887 self.top.mainloop()
888 finally:
889 self.reading = save
890 line = self.text.get("iomark", "end-1c")
891 self.resetoutput()
892 if self.canceled:
893 self.canceled = 0
894 raise KeyboardInterrupt
895 if self.endoffile:
896 self.endoffile = 0
897 return ""
898 return line
899
900 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000901 return True
David Scherer7aced172000-08-15 01:13:23 +0000902
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000903 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000904 try:
905 if self.text.compare("sel.first", "!=", "sel.last"):
906 return # Active selection -- always use default binding
907 except:
908 pass
909 if not (self.executing or self.reading):
910 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000911 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000912 self.showprompt()
913 return "break"
914 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000915 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000916 if self.reading:
917 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000918 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000919 if self.interp.getdebugger():
920 self.interp.restart_subprocess()
921 else:
922 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000923 return "break"
924
925 def eof_callback(self, event):
926 if self.executing and not self.reading:
927 return # Let the default binding (delete next char) take over
928 if not (self.text.compare("iomark", "==", "insert") and
929 self.text.compare("insert", "==", "end-1c")):
930 return # Let the default binding (delete next char) take over
931 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000932 self.resetoutput()
933 self.close()
934 else:
935 self.canceled = 0
936 self.endoffile = 1
937 self.top.quit()
938 return "break"
939
940 def home_callback(self, event):
941 if event.state != 0 and event.keysym == "Home":
942 return # <Modifier-Home>; fall back to class binding
943 if self.text.compare("iomark", "<=", "insert") and \
944 self.text.compare("insert linestart", "<=", "iomark"):
945 self.text.mark_set("insert", "iomark")
946 self.text.tag_remove("sel", "1.0", "end")
947 self.text.see("insert")
948 return "break"
949
950 def linefeed_callback(self, event):
951 # Insert a linefeed without entering anything (still autoindented)
952 if self.reading:
953 self.text.insert("insert", "\n")
954 self.text.see("insert")
955 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000956 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000957 return "break"
958
959 def enter_callback(self, event):
960 if self.executing and not self.reading:
961 return # Let the default binding (insert '\n') take over
962 # If some text is selected, recall the selection
963 # (but only if this before the I/O mark)
964 try:
965 sel = self.text.get("sel.first", "sel.last")
966 if sel:
967 if self.text.compare("sel.last", "<=", "iomark"):
968 self.recall(sel)
969 return "break"
970 except:
971 pass
972 # If we're strictly before the line containing iomark, recall
973 # the current line, less a leading prompt, less leading or
974 # trailing whitespace
975 if self.text.compare("insert", "<", "iomark linestart"):
976 # Check if there's a relevant stdin range -- if so, use it
977 prev = self.text.tag_prevrange("stdin", "insert")
978 if prev and self.text.compare("insert", "<", prev[1]):
979 self.recall(self.text.get(prev[0], prev[1]))
980 return "break"
981 next = self.text.tag_nextrange("stdin", "insert")
982 if next and self.text.compare("insert lineend", ">=", next[0]):
983 self.recall(self.text.get(next[0], next[1]))
984 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000985 # No stdin mark -- just get the current line, less any prompt
986 line = self.text.get("insert linestart", "insert lineend")
987 last_line_of_prompt = sys.ps1.split('\n')[-1]
988 if line.startswith(last_line_of_prompt):
989 line = line[len(last_line_of_prompt):]
990 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000991 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000992 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000993 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000994 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000995 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000996 # If we're in the current input and there's only whitespace
997 # beyond the cursor, erase that whitespace first
998 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000999 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001000 self.text.delete("insert", "end-1c")
1001 # If we're in the current input before its last line,
1002 # insert a newline right at the insert point
1003 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001004 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001005 return "break"
1006 # We're in the last line; append a newline and submit it
1007 self.text.mark_set("insert", "end-1c")
1008 if self.reading:
1009 self.text.insert("insert", "\n")
1010 self.text.see("insert")
1011 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001012 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001013 self.text.tag_add("stdin", "iomark", "end-1c")
1014 self.text.update_idletasks()
1015 if self.reading:
1016 self.top.quit() # Break out of recursive mainloop() in raw_input()
1017 else:
1018 self.runit()
1019 return "break"
1020
1021 def recall(self, s):
1022 if self.history:
1023 self.history.recall(s)
1024
1025 def runit(self):
1026 line = self.text.get("iomark", "end-1c")
1027 # Strip off last newline and surrounding whitespace.
1028 # (To allow you to hit return twice to end a statement.)
1029 i = len(line)
1030 while i > 0 and line[i-1] in " \t":
1031 i = i-1
1032 if i > 0 and line[i-1] == "\n":
1033 i = i-1
1034 while i > 0 and line[i-1] in " \t":
1035 i = i-1
1036 line = line[:i]
1037 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001038
David Scherer7aced172000-08-15 01:13:23 +00001039 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001040 if self.interp.rpcclt:
1041 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001042 try:
1043 sys.last_traceback
1044 except:
1045 tkMessageBox.showerror("No stack trace",
1046 "There is no stack trace yet.\n"
1047 "(sys.last_traceback is not defined)",
1048 master=self.text)
1049 return
1050 from StackViewer import StackBrowser
1051 sv = StackBrowser(self.root, self.flist)
1052
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001053 def view_restart_mark(self, event=None):
1054 self.text.see("iomark")
1055 self.text.see("restart")
1056
1057 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001058 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001059
David Scherer7aced172000-08-15 01:13:23 +00001060 def showprompt(self):
1061 self.resetoutput()
1062 try:
1063 s = str(sys.ps1)
1064 except:
1065 s = ""
1066 self.console.write(s)
1067 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001068 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001069 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001070
1071 def resetoutput(self):
1072 source = self.text.get("iomark", "end-1c")
1073 if self.history:
1074 self.history.history_store(source)
1075 if self.text.get("end-2c") != "\n":
1076 self.text.insert("end-1c", "\n")
1077 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001078 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001079 sys.stdout.softspace = 0
1080
1081 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001082 try:
1083 self.text.mark_gravity("iomark", "right")
1084 OutputWindow.write(self, s, tags, "iomark")
1085 self.text.mark_gravity("iomark", "left")
1086 except:
1087 pass
David Scherer7aced172000-08-15 01:13:23 +00001088 if self.canceled:
1089 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001090 if not use_subprocess:
1091 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001092
1093class PseudoFile:
1094
1095 def __init__(self, shell, tags):
1096 self.shell = shell
1097 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001098 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001099
1100 def write(self, s):
1101 self.shell.write(s, self.tags)
1102
1103 def writelines(self, l):
1104 map(self.write, l)
1105
1106 def flush(self):
1107 pass
1108
1109 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001110 return True
David Scherer7aced172000-08-15 01:13:23 +00001111
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001112
David Scherer7aced172000-08-15 01:13:23 +00001113usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001114
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001115USAGE: idle [-deins] [-t title] [file]*
1116 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1117 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001118
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001119 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001120 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001121
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001122The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001123
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001124 -e open an edit window
1125 -i open a shell window
1126
1127The following options imply -i and will open a shell:
1128
1129 -c cmd run the command in a shell, or
1130 -r file run script from file
1131
1132 -d enable the debugger
1133 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1134 -t title set title of shell window
1135
1136A default edit window will be bypassed when -c, -r, or - are used.
1137
1138[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1139
1140Examples:
1141
1142idle
1143 Open an edit window or shell depending on IDLE's configuration.
1144
1145idle foo.py foobar.py
1146 Edit the files, also open a shell if configured to start with shell.
1147
1148idle -est "Baz" foo.py
1149 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1150 window with the title "Baz".
1151
1152idle -c "import sys; print sys.argv" "foo"
1153 Open a shell window and run the command, passing "-c" in sys.argv[0]
1154 and "foo" in sys.argv[1].
1155
1156idle -d -s -r foo.py "Hello World"
1157 Open a shell window, run a startup script, enable the debugger, and
1158 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1159 sys.argv[1].
1160
1161echo "import sys; print sys.argv" | idle - "foobar"
1162 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1163 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001164"""
1165
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001166def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001167 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001168
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001169 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001170 enable_shell = False
1171 enable_edit = False
1172 debug = False
1173 cmd = None
1174 script = None
1175 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001176 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001177 sys.ps1
1178 except AttributeError:
1179 sys.ps1 = '>>> '
1180 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001181 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001182 except getopt.error, msg:
1183 sys.stderr.write("Error: %s\n" % str(msg))
1184 sys.stderr.write(usage_msg)
1185 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001186 for o, a in opts:
1187 if o == '-c':
1188 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001189 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001190 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001191 debug = True
1192 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001193 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001194 enable_edit = True
1195 if o == '-h':
1196 sys.stdout.write(usage_msg)
1197 sys.exit()
1198 if o == '-i':
1199 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001200 if o == '-n':
1201 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001202 if o == '-r':
1203 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001204 if os.path.isfile(script):
1205 pass
1206 else:
1207 print "No script file: ", script
1208 sys.exit()
1209 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001210 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001211 startup = True
1212 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001213 if o == '-t':
1214 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001215 enable_shell = True
1216 if args and args[0] == '-':
1217 cmd = sys.stdin.read()
1218 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001219 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001220 for i in range(len(sys.path)):
1221 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001222 if args and args[0] == '-':
1223 sys.argv = [''] + args[1:]
1224 elif cmd:
1225 sys.argv = ['-c'] + args
1226 elif script:
1227 sys.argv = [script] + args
1228 elif args:
1229 enable_edit = True
1230 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001231 for filename in args:
1232 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001233 for dir in pathx:
1234 dir = os.path.abspath(dir)
1235 if not dir in sys.path:
1236 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001237 else:
1238 dir = os.getcwd()
1239 if not dir in sys.path:
1240 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001241 # check the IDLE settings configuration (but command line overrides)
1242 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001243 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001244 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001245 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001246 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001247 root = Tk(className="Idle")
1248 fixwordbreaks(root)
1249 root.withdraw()
1250 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001251 if enable_edit:
1252 if not (cmd or script):
1253 for filename in args:
1254 flist.open(filename)
1255 if not args:
1256 flist.new()
1257 if enable_shell:
1258 flist.open_shell()
1259 elif enable_shell:
1260 flist.pyshell = PyShell(flist)
1261 flist.pyshell.begin()
1262 shell = flist.pyshell
1263 # handle remaining options:
1264 if debug:
1265 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001266 if startup:
1267 filename = os.environ.get("IDLESTARTUP") or \
1268 os.environ.get("PYTHONSTARTUP")
1269 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001270 shell.interp.execfile(filename)
1271 if cmd or script:
1272 shell.interp.runcommand("""if 1:
1273 import sys as _sys
1274 _sys.argv = %s
1275 del _sys
1276 \n""" % `sys.argv`)
1277 if cmd:
1278 shell.interp.execsource(cmd)
1279 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001280 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001281 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001282 root.mainloop()
1283 root.destroy()
1284
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001285
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001286def display_port_binding_error():
1287 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001288\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001289
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001290IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1291its Python execution server. IDLE is unable to bind to this port, and so
1292cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001293
1294 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001295 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001296 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001297
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001298Run IDLE with the -n command line switch to start without a subprocess
1299and refer to Help/IDLE Help "Running without a subprocess" for further
1300details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001301"""
David Scherer7aced172000-08-15 01:13:23 +00001302
1303if __name__ == "__main__":
1304 main()