blob: 34780041182b8ca92812c341fda5e4f1fd60cb5b [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
22from EditorWindow import EditorWindow, fixwordbreaks
23from FileList import FileList
24from ColorDelegator import ColorDelegator
25from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000026from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000027from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000028import idlever
29
Chui Tey5d2af632002-05-26 13:36:41 +000030import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000031import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000032import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000033
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000034IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000035LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000036
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000037try:
38 from signal import SIGTERM
39except ImportError:
40 SIGTERM = 15
41
Chui Tey5d2af632002-05-26 13:36:41 +000042# Change warnings module to write to sys.__stderr__
43try:
44 import warnings
45except ImportError:
46 pass
47else:
48 def idle_showwarning(message, category, filename, lineno):
49 file = sys.__stderr__
50 file.write(warnings.formatwarning(message, category, filename, lineno))
51 warnings.showwarning = idle_showwarning
52
Kurt B. Kaiser81885592002-11-29 22:10:53 +000053def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000054 """Extend linecache.checkcache to preserve the <pyshell#...> entries
55
Kurt B. Kaiser81885592002-11-29 22:10:53 +000056 Rather than repeating the linecache code, patch it to save the pyshell#
57 entries, call the original linecache.checkcache(), and then restore the
58 saved entries. Assigning the orig_checkcache keyword arg freezes its value
59 at definition time to the (original) method linecache.checkcache(), i.e.
60 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000061
62 """
David Scherer7aced172000-08-15 01:13:23 +000063 cache = linecache.cache
64 save = {}
65 for filename in cache.keys():
66 if filename[:1] + filename[-1:] == '<>':
67 save[filename] = cache[filename]
68 orig_checkcache()
69 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000070
Kurt B. Kaiser81885592002-11-29 22:10:53 +000071# Patch linecache.checkcache():
72linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000073
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000074
David Scherer7aced172000-08-15 01:13:23 +000075class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000076 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077
David Scherer7aced172000-08-15 01:13:23 +000078 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000079 self.breakpoints = []
David Scherer7aced172000-08-15 01:13:23 +000080 apply(EditorWindow.__init__, (self,) + args)
81 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000082 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +000083 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
84
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000085 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
86 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +000087 # whenever a file is changed, restore breakpoints
88 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000089 def filename_changed_hook(old_hook=self.io.filename_change_hook,
90 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +000091 self.restore_file_breaks()
92 old_hook()
93 self.io.set_filename_change_hook(filename_changed_hook)
94
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000095 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
96 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +000097
Chui Teya2adb0f2002-11-04 22:14:54 +000098 def set_breakpoint(self, lineno):
99 text = self.text
100 filename = self.io.filename
101 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
102 try:
103 i = self.breakpoints.index(lineno)
104 except ValueError: # only add if missing, i.e. do once
105 self.breakpoints.append(lineno)
106 try: # update the subprocess debugger
107 debug = self.flist.pyshell.interp.debugger
108 debug.set_breakpoint_here(filename, lineno)
109 except: # but debugger may not be active right now....
110 pass
111
David Scherer7aced172000-08-15 01:13:23 +0000112 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000113 text = self.text
114 filename = self.io.filename
115 if not filename:
116 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000117 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000118 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000119 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000120
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000121 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000122 text = self.text
123 filename = self.io.filename
124 if not filename:
125 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000126 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000127 lineno = int(float(text.index("insert")))
128 try:
129 self.breakpoints.remove(lineno)
130 except:
131 pass
132 text.tag_remove("BREAK", "insert linestart",\
133 "insert lineend +1char")
134 try:
135 debug = self.flist.pyshell.interp.debugger
136 debug.clear_breakpoint_here(filename, lineno)
137 except:
138 pass
139
140 def clear_file_breaks(self):
141 if self.breakpoints:
142 text = self.text
143 filename = self.io.filename
144 if not filename:
145 text.bell()
146 return
147 self.breakpoints = []
148 text.tag_remove("BREAK", "1.0", END)
149 try:
150 debug = self.flist.pyshell.interp.debugger
151 debug.clear_file_breaks(filename)
152 except:
153 pass
154
Chui Teya2adb0f2002-11-04 22:14:54 +0000155 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000156 "Save breakpoints when file is saved"
157 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
158 # be run. The breaks are saved at that time. If we introduce
159 # a temporary file save feature the save breaks functionality
160 # needs to be re-verified, since the breaks at the time the
161 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000162 # permanent save of the file. Currently, a break introduced
163 # after a save will be effective, but not persistent.
164 # This is necessary to keep the saved breaks synched with the
165 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000166 #
167 # Breakpoints are set as tagged ranges in the text. Certain
168 # kinds of edits cause these ranges to be deleted: Inserting
169 # or deleting a line just before a breakpoint, and certain
170 # deletions prior to a breakpoint. These issues need to be
171 # investigated and understood. It's not clear if they are
172 # Tk issues or IDLE issues, or whether they can actually
173 # be fixed. Since a modified file has to be saved before it is
174 # run, and since self.breakpoints (from which the subprocess
175 # debugger is loaded) is updated during the save, the visible
176 # breaks stay synched with the subprocess even if one of these
177 # unexpected breakpoint deletions occurs.
178 breaks = self.breakpoints
179 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000180 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000181 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000182 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000183 lines = []
184 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000185 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000186 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000187 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000188 self.update_breakpoints()
189 breaks = self.breakpoints
190 if breaks:
191 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000192 new_file.close()
193
194 def restore_file_breaks(self):
195 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000196 filename = self.io.filename
197 if filename is None:
198 return
Chui Tey69371d62002-11-04 23:39:45 +0000199 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000200 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000201 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000202 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000203 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000204 for breakpoint_linenumber in breakpoint_linenumbers:
205 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000206
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000207 def update_breakpoints(self):
208 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 ranges = text.tag_ranges("BREAK")
211 linenumber_list = self.ranges_to_linenumbers(ranges)
212 self.breakpoints = linenumber_list
213
214 def ranges_to_linenumbers(self, ranges):
215 lines = []
216 for index in range(0, len(ranges), 2):
217 lineno = int(float(ranges[index]))
218 end = int(float(ranges[index+1]))
219 while lineno < end:
220 lines.append(lineno)
221 lineno += 1
222 return lines
223
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000224# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225# def saved_change_hook(self):
226# "Extend base method - clear breaks if module is modified"
227# if not self.get_saved():
228# self.clear_file_breaks()
229# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000230
231 def _close(self):
232 "Extend base method - clear breaks when module is closed"
233 self.clear_file_breaks()
234 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000235
David Scherer7aced172000-08-15 01:13:23 +0000236
237class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000238 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000239
240 EditorWindow = PyShellEditorWindow
241
242 pyshell = None
243
244 def open_shell(self, event=None):
245 if self.pyshell:
246 self.pyshell.wakeup()
247 else:
248 self.pyshell = PyShell(self)
249 self.pyshell.begin()
250 return self.pyshell
251
252
253class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000254 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000255
Steven M. Gavab77d3432002-03-02 07:16:21 +0000256 def __init__(self):
257 ColorDelegator.__init__(self)
258 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000259
260 def recolorize_main(self):
261 self.tag_remove("TODO", "1.0", "iomark")
262 self.tag_add("SYNC", "1.0", "iomark")
263 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000264
Steven M. Gavab77d3432002-03-02 07:16:21 +0000265 def LoadTagDefs(self):
266 ColorDelegator.LoadTagDefs(self)
267 theme = idleConf.GetOption('main','Theme','name')
268 self.tagdefs.update({
269 "stdin": {'background':None,'foreground':None},
270 "stdout": idleConf.GetHighlight(theme, "stdout"),
271 "stderr": idleConf.GetHighlight(theme, "stderr"),
272 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000273 None: idleConf.GetHighlight(theme, "normal"),
274 })
David Scherer7aced172000-08-15 01:13:23 +0000275
David Scherer7aced172000-08-15 01:13:23 +0000276class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000277 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000278
279 def insert(self, index, chars, tags=None):
280 try:
281 if self.delegate.compare(index, "<", "iomark"):
282 self.delegate.bell()
283 return
284 except TclError:
285 pass
286 UndoDelegator.insert(self, index, chars, tags)
287
288 def delete(self, index1, index2=None):
289 try:
290 if self.delegate.compare(index1, "<", "iomark"):
291 self.delegate.bell()
292 return
293 except TclError:
294 pass
295 UndoDelegator.delete(self, index1, index2)
296
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000297
298class MyRPCClient(rpc.RPCClient):
299
300 def handle_EOF(self):
301 "Override the base class - just re-raise EOFError"
302 raise EOFError
303
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000304
David Scherer7aced172000-08-15 01:13:23 +0000305class ModifiedInterpreter(InteractiveInterpreter):
306
307 def __init__(self, tkconsole):
308 self.tkconsole = tkconsole
309 locals = sys.modules['__main__'].__dict__
310 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000311 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000312 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000313 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000314
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000315 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000316 rpcclt = None
317 rpcpid = None
318
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000319 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000320 args = self.subprocess_arglist
Chui Tey5d2af632002-05-26 13:36:41 +0000321 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000322
Tony Lowndsf53dec22002-12-20 04:24:43 +0000323 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000324 w = ['-W' + s for s in sys.warnoptions]
325 # Maybe IDLE is installed and is being accessed via sys.path,
326 # or maybe it's not installed and the idle.py script is being
327 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000328 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
329 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000330 if __name__ == 'idlelib.PyShell':
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000331 command = "__import__('idlelib.run').run.main(" + `del_exitf` +")"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000332 else:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000333 command = "__import__('run').main(" + `del_exitf` + ")"
Tony Lownds2398d572003-05-13 15:28:21 +0000334 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000335
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000336 def start_subprocess(self):
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000337 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000338 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000339 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000340 time.sleep(i)
341 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000342 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000343 break
344 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000345 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000346 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000347 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000348 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000349 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000350 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000351 # Accept the connection from the Python execution server
352 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000353 self.rpcclt.register("stdin", self.tkconsole)
354 self.rpcclt.register("stdout", self.tkconsole.stdout)
355 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000356 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000357 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000358 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000359 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000360 self.poll_subprocess()
361
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000362 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000363 if self.restarting:
364 return
365 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000366 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000367 debug = self.getdebugger()
368 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000369 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000370 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000371 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
372 except:
373 pass
374 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000375 self.rpcclt.close()
376 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000377 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000378 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000379 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000380 self.spawn_subprocess()
381 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000382 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000383 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000384 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000385 if was_executing:
386 console.write('\n')
387 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000388 halfbar = ((int(console.width) - 16) // 2) * '='
389 console.write(halfbar + ' RESTART ' + halfbar)
390 console.text.mark_set("restart", "end-1c")
391 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000392 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000393 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000394 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000395 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000396 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000397 # reload remote debugger breakpoints for all PyShellEditWindows
398 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000399 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000400
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000401 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000402 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000403
404 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000405 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000406
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000407 def kill_subprocess(self):
408 self.rpcclt.close()
409 self.unix_terminate()
410 self.tkconsole.executing = False
411 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000412
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000413 def unix_terminate(self):
414 "UNIX: make sure subprocess is terminated and collect status"
415 if hasattr(os, 'kill'):
416 try:
417 os.kill(self.rpcpid, SIGTERM)
418 except OSError:
419 # process already terminated:
420 return
421 else:
422 try:
423 os.waitpid(self.rpcpid, 0)
424 except OSError:
425 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000426
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000427 def transfer_path(self):
428 self.runcommand("""if 1:
429 import sys as _sys
430 _sys.path = %s
431 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000432 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
433 __builtins__.quit = __builtins__.exit = _msg
434 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000435 \n""" % `sys.path`)
436
Chui Tey5d2af632002-05-26 13:36:41 +0000437 active_seq = None
438
439 def poll_subprocess(self):
440 clt = self.rpcclt
441 if clt is None:
442 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000444 response = clt.pollresponse(self.active_seq, wait=0.05)
445 except (EOFError, IOError, KeyboardInterrupt):
446 # lost connection or subprocess terminated itself, restart
447 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000448 if self.tkconsole.closing:
449 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000450 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000452 if response:
453 self.tkconsole.resetoutput()
454 self.active_seq = None
455 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000456 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000457 if how == "OK":
458 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000459 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000460 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000461 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
462 self.remote_stack_viewer()
463 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000464 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
465 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000466 print >>console, errmsg, what
467 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000468 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000469 # Reschedule myself
470 if not self.tkconsole.closing:
471 self.tkconsole.text.after(self.tkconsole.pollinterval,
472 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000473
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000474 debugger = None
475
476 def setdebugger(self, debugger):
477 self.debugger = debugger
478
479 def getdebugger(self):
480 return self.debugger
481
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000482 def open_remote_stack_viewer(self):
483 """Initiate the remote stack viewer from a separate thread.
484
485 This method is called from the subprocess, and by returning from this
486 method we allow the subprocess to unblock. After a bit the shell
487 requests the subprocess to open the remote stack viewer which returns a
488 static object looking at the last exceptiopn. It is queried through
489 the RPC mechanism.
490
491 """
492 self.tkconsole.text.after(300, self.remote_stack_viewer)
493 return
494
Chui Tey5d2af632002-05-26 13:36:41 +0000495 def remote_stack_viewer(self):
496 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000497 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000498 if oid is None:
499 self.tkconsole.root.bell()
500 return
501 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
502 from TreeWidget import ScrolledCanvas, TreeNode
503 top = Toplevel(self.tkconsole.root)
504 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
505 sc.frame.pack(expand=1, fill="both")
506 node = TreeNode(sc.canvas, None, item)
507 node.expand()
508 # XXX Should GC the remote tree when closing the window
509
David Scherer7aced172000-08-15 01:13:23 +0000510 gid = 0
511
512 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000513 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000514 filename = self.stuffsource(source)
515 self.execfile(filename, source)
516
517 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000518 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000519 if source is None:
520 source = open(filename, "r").read()
521 try:
522 code = compile(source, filename, "exec")
523 except (OverflowError, SyntaxError):
524 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000525 tkerr = self.tkconsole.stderr
526 print>>tkerr, '*** Error in script or command!\n'
527 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000528 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000529 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000530 else:
531 self.runcode(code)
532
533 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000534 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000535 filename = self.stuffsource(source)
536 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000537 self.save_warnings_filters = warnings.filters[:]
538 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000539 if isinstance(source, types.UnicodeType):
540 import IOBinding
541 try:
542 source = source.encode(IOBinding.encoding)
543 except UnicodeError:
544 self.tkconsole.resetoutput()
545 self.write("Unsupported characters in input")
546 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000547 try:
548 return InteractiveInterpreter.runsource(self, source, filename)
549 finally:
550 if self.save_warnings_filters is not None:
551 warnings.filters[:] = self.save_warnings_filters
552 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000553
554 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000555 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000556 filename = "<pyshell#%d>" % self.gid
557 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000558 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000559 linecache.cache[filename] = len(source)+1, 0, lines, filename
560 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000561
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000562 def prepend_syspath(self, filename):
563 "Prepend sys.path with file's directory if not already included"
564 self.runcommand("""if 1:
565 _filename = %s
566 import sys as _sys
567 from os.path import dirname as _dirname
568 _dir = _dirname(_filename)
569 if not _dir in _sys.path:
570 _sys.path.insert(0, _dir)
571 del _filename, _sys, _dirname, _dir
572 \n""" % `filename`)
573
David Scherer7aced172000-08-15 01:13:23 +0000574 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000575 """Extend base class method: Add Colorizing
576
577 Color the offending position instead of printing it and pointing at it
578 with a caret.
579
580 """
David Scherer7aced172000-08-15 01:13:23 +0000581 text = self.tkconsole.text
582 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000583 if stuff:
584 msg, lineno, offset, line = stuff
585 if lineno == 1:
586 pos = "iomark + %d chars" % (offset-1)
587 else:
588 pos = "iomark linestart + %d lines + %d chars" % \
589 (lineno-1, offset-1)
590 text.tag_add("ERROR", pos)
591 text.see(pos)
592 char = text.get(pos)
593 if char and char in IDENTCHARS:
594 text.tag_add("ERROR", pos + " wordstart", pos)
595 self.tkconsole.resetoutput()
596 self.write("SyntaxError: %s\n" % str(msg))
597 else:
David Scherer7aced172000-08-15 01:13:23 +0000598 self.tkconsole.resetoutput()
599 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000600 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000601
602 def unpackerror(self):
603 type, value, tb = sys.exc_info()
604 ok = type is SyntaxError
605 if ok:
606 try:
607 msg, (dummy_filename, lineno, offset, line) = value
608 except:
609 ok = 0
610 if ok:
611 return msg, lineno, offset, line
612 else:
613 return None
614
615 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000616 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000617 self.tkconsole.resetoutput()
618 self.checklinecache()
619 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000620 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
621 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000622
623 def checklinecache(self):
624 c = linecache.cache
625 for key in c.keys():
626 if key[:1] + key[-1:] != "<>":
627 del c[key]
628
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000629 def display_executing_dialog(self):
630 tkMessageBox.showerror(
631 "Already executing",
632 "The Python Shell window is already executing a command; "
633 "please wait until it is finished.",
634 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000635
Chui Tey5d2af632002-05-26 13:36:41 +0000636 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000637 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000638 # The code better not raise an exception!
639 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000640 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000641 return 0
642 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000643 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000644 else:
645 exec code in self.locals
646 return 1
647
David Scherer7aced172000-08-15 01:13:23 +0000648 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000649 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000650 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000651 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000652 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000653 if self.save_warnings_filters is not None:
654 warnings.filters[:] = self.save_warnings_filters
655 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000656 debugger = self.debugger
657 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000658 self.tkconsole.beginexecuting()
659 try:
660 if not debugger and self.rpcclt is not None:
661 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
662 (code,), {})
663 elif debugger:
664 debugger.run(code, self.locals)
665 else:
666 exec code in self.locals
667 except SystemExit:
668 if tkMessageBox.askyesno(
669 "Exit?",
670 "Do you want to exit altogether?",
671 default="yes",
672 master=self.tkconsole.text):
673 raise
674 else:
675 self.showtraceback()
676 except:
David Scherer7aced172000-08-15 01:13:23 +0000677 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000678 finally:
679 if not use_subprocess:
680 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000681
682 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000683 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000684 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000685
David Scherer7aced172000-08-15 01:13:23 +0000686class PyShell(OutputWindow):
687
688 shell_title = "Python Shell"
689
690 # Override classes
691 ColorDelegator = ModifiedColorDelegator
692 UndoDelegator = ModifiedUndoDelegator
693
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000694 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000695 menu_specs = [
696 ("file", "_File"),
697 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000698 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000699 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000700 ("windows", "_Windows"),
701 ("help", "_Help"),
702 ]
David Scherer7aced172000-08-15 01:13:23 +0000703
704 # New classes
705 from IdleHistory import History
706
707 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000708 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000709 ms = self.menu_specs
710 if ms[2][0] != "shell":
711 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000712 self.interp = ModifiedInterpreter(self)
713 if flist is None:
714 root = Tk()
715 fixwordbreaks(root)
716 root.withdraw()
717 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000718 #
David Scherer7aced172000-08-15 01:13:23 +0000719 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000720 #
David Scherer7aced172000-08-15 01:13:23 +0000721 import __builtin__
722 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000723 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000724 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000725 #
David Scherer7aced172000-08-15 01:13:23 +0000726 text = self.text
727 text.configure(wrap="char")
728 text.bind("<<newline-and-indent>>", self.enter_callback)
729 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
730 text.bind("<<interrupt-execution>>", self.cancel_callback)
731 text.bind("<<beginning-of-line>>", self.home_callback)
732 text.bind("<<end-of-file>>", self.eof_callback)
733 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000734 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000735 text.bind("<<open-python-shell>>", self.flist.open_shell)
736 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000737 if use_subprocess:
738 text.bind("<<view-restart>>", self.view_restart_mark)
739 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000740 #
David Scherer7aced172000-08-15 01:13:23 +0000741 self.save_stdout = sys.stdout
742 self.save_stderr = sys.stderr
743 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000744 self.stdout = PseudoFile(self, "stdout")
745 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000746 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000747 if not use_subprocess:
748 sys.stdout = self.stdout
749 sys.stderr = self.stderr
750 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000751 #
David Scherer7aced172000-08-15 01:13:23 +0000752 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000753 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000754 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000755 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000756 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000757
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000758 reading = False
759 executing = False
760 canceled = False
761 endoffile = False
762 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000763
764 def toggle_debugger(self, event=None):
765 if self.executing:
766 tkMessageBox.showerror("Don't debug now",
767 "You can only toggle the debugger when idle",
768 master=self.text)
769 self.set_debugger_indicator()
770 return "break"
771 else:
772 db = self.interp.getdebugger()
773 if db:
774 self.close_debugger()
775 else:
776 self.open_debugger()
777
778 def set_debugger_indicator(self):
779 db = self.interp.getdebugger()
780 self.setvar("<<toggle-debugger>>", not not db)
781
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000782 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000783 pass # All we need is the variable
784
785 def close_debugger(self):
786 db = self.interp.getdebugger()
787 if db:
788 self.interp.setdebugger(None)
789 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000790 if self.interp.rpcclt:
791 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000792 self.resetoutput()
793 self.console.write("[DEBUG OFF]\n")
794 sys.ps1 = ">>> "
795 self.showprompt()
796 self.set_debugger_indicator()
797
798 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000799 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000800 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
801 self)
802 else:
803 dbg_gui = Debugger.Debugger(self)
804 self.interp.setdebugger(dbg_gui)
805 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000806 sys.ps1 = "[DEBUG ON]\n>>> "
807 self.showprompt()
808 self.set_debugger_indicator()
809
David Scherer7aced172000-08-15 01:13:23 +0000810 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000811 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000812 self.resetoutput()
813 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000814
815 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000816 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000817 self.executing = 0
818 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000819 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000820
821 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000822 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000823 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000824 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000825 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000826 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000827 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000828 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000829 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000830 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000831 self.closing = True
832 # Wait for poll_subprocess() rescheduling to stop
833 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000834
835 def close2(self):
836 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000837
838 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000839 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000840 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000841 if use_subprocess:
842 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000843 # Restore std streams
844 sys.stdout = self.save_stdout
845 sys.stderr = self.save_stderr
846 sys.stdin = self.save_stdin
847 # Break cycles
848 self.interp = None
849 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000850 self.flist.pyshell = None
851 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000852 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000853
854 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000855 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000856 return True
David Scherer7aced172000-08-15 01:13:23 +0000857
858 def short_title(self):
859 return self.shell_title
860
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000861 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000862 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000863
David Scherer7aced172000-08-15 01:13:23 +0000864 def begin(self):
865 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000866 if use_subprocess:
867 nosub = ''
868 else:
869 nosub = "==== No Subprocess ===="
Kurt B. Kaiserae8bbff2003-06-14 03:23:56 +0000870 self.write("Python %s on %s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000871 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000872 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000873 self.showprompt()
874 import Tkinter
875 Tkinter._default_root = None
876
877 def interact(self):
878 self.begin()
879 self.top.mainloop()
880
881 def readline(self):
882 save = self.reading
883 try:
884 self.reading = 1
885 self.top.mainloop()
886 finally:
887 self.reading = save
888 line = self.text.get("iomark", "end-1c")
889 self.resetoutput()
890 if self.canceled:
891 self.canceled = 0
892 raise KeyboardInterrupt
893 if self.endoffile:
894 self.endoffile = 0
895 return ""
896 return line
897
898 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000899 return True
David Scherer7aced172000-08-15 01:13:23 +0000900
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000901 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000902 try:
903 if self.text.compare("sel.first", "!=", "sel.last"):
904 return # Active selection -- always use default binding
905 except:
906 pass
907 if not (self.executing or self.reading):
908 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000909 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000910 self.showprompt()
911 return "break"
912 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000913 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000914 if self.reading:
915 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000916 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000917 if self.interp.getdebugger():
918 self.interp.restart_subprocess()
919 else:
920 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000921 return "break"
922
923 def eof_callback(self, event):
924 if self.executing and not self.reading:
925 return # Let the default binding (delete next char) take over
926 if not (self.text.compare("iomark", "==", "insert") and
927 self.text.compare("insert", "==", "end-1c")):
928 return # Let the default binding (delete next char) take over
929 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000930 self.resetoutput()
931 self.close()
932 else:
933 self.canceled = 0
934 self.endoffile = 1
935 self.top.quit()
936 return "break"
937
938 def home_callback(self, event):
939 if event.state != 0 and event.keysym == "Home":
940 return # <Modifier-Home>; fall back to class binding
941 if self.text.compare("iomark", "<=", "insert") and \
942 self.text.compare("insert linestart", "<=", "iomark"):
943 self.text.mark_set("insert", "iomark")
944 self.text.tag_remove("sel", "1.0", "end")
945 self.text.see("insert")
946 return "break"
947
948 def linefeed_callback(self, event):
949 # Insert a linefeed without entering anything (still autoindented)
950 if self.reading:
951 self.text.insert("insert", "\n")
952 self.text.see("insert")
953 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000954 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000955 return "break"
956
957 def enter_callback(self, event):
958 if self.executing and not self.reading:
959 return # Let the default binding (insert '\n') take over
960 # If some text is selected, recall the selection
961 # (but only if this before the I/O mark)
962 try:
963 sel = self.text.get("sel.first", "sel.last")
964 if sel:
965 if self.text.compare("sel.last", "<=", "iomark"):
966 self.recall(sel)
967 return "break"
968 except:
969 pass
970 # If we're strictly before the line containing iomark, recall
971 # the current line, less a leading prompt, less leading or
972 # trailing whitespace
973 if self.text.compare("insert", "<", "iomark linestart"):
974 # Check if there's a relevant stdin range -- if so, use it
975 prev = self.text.tag_prevrange("stdin", "insert")
976 if prev and self.text.compare("insert", "<", prev[1]):
977 self.recall(self.text.get(prev[0], prev[1]))
978 return "break"
979 next = self.text.tag_nextrange("stdin", "insert")
980 if next and self.text.compare("insert lineend", ">=", next[0]):
981 self.recall(self.text.get(next[0], next[1]))
982 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000983 # No stdin mark -- just get the current line, less any prompt
984 line = self.text.get("insert linestart", "insert lineend")
985 last_line_of_prompt = sys.ps1.split('\n')[-1]
986 if line.startswith(last_line_of_prompt):
987 line = line[len(last_line_of_prompt):]
988 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000989 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000990 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000991 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000992 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000993 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000994 # If we're in the current input and there's only whitespace
995 # beyond the cursor, erase that whitespace first
996 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000997 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000998 self.text.delete("insert", "end-1c")
999 # If we're in the current input before its last line,
1000 # insert a newline right at the insert point
1001 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001002 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001003 return "break"
1004 # We're in the last line; append a newline and submit it
1005 self.text.mark_set("insert", "end-1c")
1006 if self.reading:
1007 self.text.insert("insert", "\n")
1008 self.text.see("insert")
1009 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001010 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001011 self.text.tag_add("stdin", "iomark", "end-1c")
1012 self.text.update_idletasks()
1013 if self.reading:
1014 self.top.quit() # Break out of recursive mainloop() in raw_input()
1015 else:
1016 self.runit()
1017 return "break"
1018
1019 def recall(self, s):
1020 if self.history:
1021 self.history.recall(s)
1022
1023 def runit(self):
1024 line = self.text.get("iomark", "end-1c")
1025 # Strip off last newline and surrounding whitespace.
1026 # (To allow you to hit return twice to end a statement.)
1027 i = len(line)
1028 while i > 0 and line[i-1] in " \t":
1029 i = i-1
1030 if i > 0 and line[i-1] == "\n":
1031 i = i-1
1032 while i > 0 and line[i-1] in " \t":
1033 i = i-1
1034 line = line[:i]
1035 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001036
David Scherer7aced172000-08-15 01:13:23 +00001037 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001038 if self.interp.rpcclt:
1039 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001040 try:
1041 sys.last_traceback
1042 except:
1043 tkMessageBox.showerror("No stack trace",
1044 "There is no stack trace yet.\n"
1045 "(sys.last_traceback is not defined)",
1046 master=self.text)
1047 return
1048 from StackViewer import StackBrowser
1049 sv = StackBrowser(self.root, self.flist)
1050
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001051 def view_restart_mark(self, event=None):
1052 self.text.see("iomark")
1053 self.text.see("restart")
1054
1055 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001056 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001057
David Scherer7aced172000-08-15 01:13:23 +00001058 def showprompt(self):
1059 self.resetoutput()
1060 try:
1061 s = str(sys.ps1)
1062 except:
1063 s = ""
1064 self.console.write(s)
1065 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001066 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001067 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001068
1069 def resetoutput(self):
1070 source = self.text.get("iomark", "end-1c")
1071 if self.history:
1072 self.history.history_store(source)
1073 if self.text.get("end-2c") != "\n":
1074 self.text.insert("end-1c", "\n")
1075 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001076 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001077 sys.stdout.softspace = 0
1078
1079 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001080 try:
1081 self.text.mark_gravity("iomark", "right")
1082 OutputWindow.write(self, s, tags, "iomark")
1083 self.text.mark_gravity("iomark", "left")
1084 except:
1085 pass
David Scherer7aced172000-08-15 01:13:23 +00001086 if self.canceled:
1087 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001088 if not use_subprocess:
1089 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001090
1091class PseudoFile:
1092
1093 def __init__(self, shell, tags):
1094 self.shell = shell
1095 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001096 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001097
1098 def write(self, s):
1099 self.shell.write(s, self.tags)
1100
1101 def writelines(self, l):
1102 map(self.write, l)
1103
1104 def flush(self):
1105 pass
1106
1107 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001108 return True
David Scherer7aced172000-08-15 01:13:23 +00001109
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001110
David Scherer7aced172000-08-15 01:13:23 +00001111usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001112
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001113USAGE: idle [-deins] [-t title] [file]*
1114 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1115 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001116
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001117 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001118 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001119
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001120The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001121
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001122 -e open an edit window
1123 -i open a shell window
1124
1125The following options imply -i and will open a shell:
1126
1127 -c cmd run the command in a shell, or
1128 -r file run script from file
1129
1130 -d enable the debugger
1131 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1132 -t title set title of shell window
1133
1134A default edit window will be bypassed when -c, -r, or - are used.
1135
1136[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1137
1138Examples:
1139
1140idle
1141 Open an edit window or shell depending on IDLE's configuration.
1142
1143idle foo.py foobar.py
1144 Edit the files, also open a shell if configured to start with shell.
1145
1146idle -est "Baz" foo.py
1147 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1148 window with the title "Baz".
1149
1150idle -c "import sys; print sys.argv" "foo"
1151 Open a shell window and run the command, passing "-c" in sys.argv[0]
1152 and "foo" in sys.argv[1].
1153
1154idle -d -s -r foo.py "Hello World"
1155 Open a shell window, run a startup script, enable the debugger, and
1156 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1157 sys.argv[1].
1158
1159echo "import sys; print sys.argv" | idle - "foobar"
1160 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1161 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001162"""
1163
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001164def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001165 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001166
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001167 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001168 enable_shell = False
1169 enable_edit = False
1170 debug = False
1171 cmd = None
1172 script = None
1173 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001174 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001175 sys.ps1
1176 except AttributeError:
1177 sys.ps1 = '>>> '
1178 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001179 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001180 except getopt.error, msg:
1181 sys.stderr.write("Error: %s\n" % str(msg))
1182 sys.stderr.write(usage_msg)
1183 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001184 for o, a in opts:
1185 if o == '-c':
1186 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001187 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001188 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001189 debug = True
1190 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001191 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001192 enable_edit = True
1193 if o == '-h':
1194 sys.stdout.write(usage_msg)
1195 sys.exit()
1196 if o == '-i':
1197 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001198 if o == '-n':
1199 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001200 if o == '-r':
1201 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001202 if os.path.isfile(script):
1203 pass
1204 else:
1205 print "No script file: ", script
1206 sys.exit()
1207 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001208 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001209 startup = True
1210 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001211 if o == '-t':
1212 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001213 enable_shell = True
1214 if args and args[0] == '-':
1215 cmd = sys.stdin.read()
1216 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001217 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001218 for i in range(len(sys.path)):
1219 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001220 if args and args[0] == '-':
1221 sys.argv = [''] + args[1:]
1222 elif cmd:
1223 sys.argv = ['-c'] + args
1224 elif script:
1225 sys.argv = [script] + args
1226 elif args:
1227 enable_edit = True
1228 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001229 for filename in args:
1230 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001231 for dir in pathx:
1232 dir = os.path.abspath(dir)
1233 if not dir in sys.path:
1234 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001235 else:
1236 dir = os.getcwd()
1237 if not dir in sys.path:
1238 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001239 # check the IDLE settings configuration (but command line overrides)
1240 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001241 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001242 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001243 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001244 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001245 root = Tk(className="Idle")
1246 fixwordbreaks(root)
1247 root.withdraw()
1248 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001249 if enable_edit:
1250 if not (cmd or script):
1251 for filename in args:
1252 flist.open(filename)
1253 if not args:
1254 flist.new()
1255 if enable_shell:
1256 flist.open_shell()
1257 elif enable_shell:
1258 flist.pyshell = PyShell(flist)
1259 flist.pyshell.begin()
1260 shell = flist.pyshell
1261 # handle remaining options:
1262 if debug:
1263 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001264 if startup:
1265 filename = os.environ.get("IDLESTARTUP") or \
1266 os.environ.get("PYTHONSTARTUP")
1267 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001268 shell.interp.execfile(filename)
1269 if cmd or script:
1270 shell.interp.runcommand("""if 1:
1271 import sys as _sys
1272 _sys.argv = %s
1273 del _sys
1274 \n""" % `sys.argv`)
1275 if cmd:
1276 shell.interp.execsource(cmd)
1277 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001278 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001279 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001280 root.mainloop()
1281 root.destroy()
1282
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001283
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001284def display_port_binding_error():
1285 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001286\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001287
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001288IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1289its Python execution server. IDLE is unable to bind to this port, and so
1290cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001291
1292 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001293 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001294 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001295
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001296Run IDLE with the -n command line switch to start without a subprocess
1297and refer to Help/IDLE Help "Running without a subprocess" for further
1298details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001299"""
David Scherer7aced172000-08-15 01:13:23 +00001300
1301if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001302 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001303 main()