blob: a11eaa5c72adee267bd7a08611db5e41acdbe184 [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. Kaiserf06eed02002-12-11 04:42:04 +0000360 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000361 self.poll_subprocess()
362
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000363 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000364 if self.restarting:
365 return
366 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000367 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000368 debug = self.getdebugger()
369 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000370 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000371 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000372 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
373 except:
374 pass
375 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000376 self.rpcclt.close()
377 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000378 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000379 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000380 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000381 self.spawn_subprocess()
382 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000383 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000384 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000385 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000386 if was_executing:
387 console.write('\n')
388 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000389 halfbar = ((int(console.width) - 16) // 2) * '='
390 console.write(halfbar + ' RESTART ' + halfbar)
391 console.text.mark_set("restart", "end-1c")
392 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000393 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000394 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000395 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000396 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000397 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000398 # reload remote debugger breakpoints for all PyShellEditWindows
399 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000400 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000401
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000402 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000403 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000404
405 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000406 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000407
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000408 def kill_subprocess(self):
409 self.rpcclt.close()
410 self.unix_terminate()
411 self.tkconsole.executing = False
412 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000413
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000414 def unix_terminate(self):
415 "UNIX: make sure subprocess is terminated and collect status"
416 if hasattr(os, 'kill'):
417 try:
418 os.kill(self.rpcpid, SIGTERM)
419 except OSError:
420 # process already terminated:
421 return
422 else:
423 try:
424 os.waitpid(self.rpcpid, 0)
425 except OSError:
426 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000427
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000428 def transfer_path(self):
429 self.runcommand("""if 1:
430 import sys as _sys
431 _sys.path = %s
432 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000433 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
434 __builtins__.quit = __builtins__.exit = _msg
435 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000436 \n""" % `sys.path`)
437
Chui Tey5d2af632002-05-26 13:36:41 +0000438 active_seq = None
439
440 def poll_subprocess(self):
441 clt = self.rpcclt
442 if clt is None:
443 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000444 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000445 response = clt.pollresponse(self.active_seq, wait=0.05)
446 except (EOFError, IOError, KeyboardInterrupt):
447 # lost connection or subprocess terminated itself, restart
448 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000449 if self.tkconsole.closing:
450 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000453 if response:
454 self.tkconsole.resetoutput()
455 self.active_seq = None
456 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000457 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000458 if how == "OK":
459 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000460 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000461 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000462 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
463 self.remote_stack_viewer()
464 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000465 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
466 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000467 print >>console, errmsg, what
468 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000469 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000470 # Reschedule myself
471 if not self.tkconsole.closing:
472 self.tkconsole.text.after(self.tkconsole.pollinterval,
473 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000474
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000475 debugger = None
476
477 def setdebugger(self, debugger):
478 self.debugger = debugger
479
480 def getdebugger(self):
481 return self.debugger
482
Chui Tey5d2af632002-05-26 13:36:41 +0000483 def remote_stack_viewer(self):
484 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000485 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000486 if oid is None:
487 self.tkconsole.root.bell()
488 return
489 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
490 from TreeWidget import ScrolledCanvas, TreeNode
491 top = Toplevel(self.tkconsole.root)
492 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
493 sc.frame.pack(expand=1, fill="both")
494 node = TreeNode(sc.canvas, None, item)
495 node.expand()
496 # XXX Should GC the remote tree when closing the window
497
David Scherer7aced172000-08-15 01:13:23 +0000498 gid = 0
499
500 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000501 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000502 filename = self.stuffsource(source)
503 self.execfile(filename, source)
504
505 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000506 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000507 if source is None:
508 source = open(filename, "r").read()
509 try:
510 code = compile(source, filename, "exec")
511 except (OverflowError, SyntaxError):
512 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000513 tkerr = self.tkconsole.stderr
514 print>>tkerr, '*** Error in script or command!\n'
515 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000516 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000517 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000518 else:
519 self.runcode(code)
520
521 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000522 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000523 filename = self.stuffsource(source)
524 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000525 self.save_warnings_filters = warnings.filters[:]
526 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000527 if isinstance(source, types.UnicodeType):
528 import IOBinding
529 try:
530 source = source.encode(IOBinding.encoding)
531 except UnicodeError:
532 self.tkconsole.resetoutput()
533 self.write("Unsupported characters in input")
534 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000535 try:
536 return InteractiveInterpreter.runsource(self, source, filename)
537 finally:
538 if self.save_warnings_filters is not None:
539 warnings.filters[:] = self.save_warnings_filters
540 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000541
542 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000543 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000544 filename = "<pyshell#%d>" % self.gid
545 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000546 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000547 linecache.cache[filename] = len(source)+1, 0, lines, filename
548 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000549
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000550 def prepend_syspath(self, filename):
551 "Prepend sys.path with file's directory if not already included"
552 self.runcommand("""if 1:
553 _filename = %s
554 import sys as _sys
555 from os.path import dirname as _dirname
556 _dir = _dirname(_filename)
557 if not _dir in _sys.path:
558 _sys.path.insert(0, _dir)
559 del _filename, _sys, _dirname, _dir
560 \n""" % `filename`)
561
David Scherer7aced172000-08-15 01:13:23 +0000562 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000563 """Extend base class method: Add Colorizing
564
565 Color the offending position instead of printing it and pointing at it
566 with a caret.
567
568 """
David Scherer7aced172000-08-15 01:13:23 +0000569 text = self.tkconsole.text
570 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000571 if stuff:
572 msg, lineno, offset, line = stuff
573 if lineno == 1:
574 pos = "iomark + %d chars" % (offset-1)
575 else:
576 pos = "iomark linestart + %d lines + %d chars" % \
577 (lineno-1, offset-1)
578 text.tag_add("ERROR", pos)
579 text.see(pos)
580 char = text.get(pos)
581 if char and char in IDENTCHARS:
582 text.tag_add("ERROR", pos + " wordstart", pos)
583 self.tkconsole.resetoutput()
584 self.write("SyntaxError: %s\n" % str(msg))
585 else:
David Scherer7aced172000-08-15 01:13:23 +0000586 self.tkconsole.resetoutput()
587 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000588 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000589
590 def unpackerror(self):
591 type, value, tb = sys.exc_info()
592 ok = type is SyntaxError
593 if ok:
594 try:
595 msg, (dummy_filename, lineno, offset, line) = value
596 except:
597 ok = 0
598 if ok:
599 return msg, lineno, offset, line
600 else:
601 return None
602
603 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000604 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000605 self.tkconsole.resetoutput()
606 self.checklinecache()
607 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000608 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
609 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000610
611 def checklinecache(self):
612 c = linecache.cache
613 for key in c.keys():
614 if key[:1] + key[-1:] != "<>":
615 del c[key]
616
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000617 def display_executing_dialog(self):
618 tkMessageBox.showerror(
619 "Already executing",
620 "The Python Shell window is already executing a command; "
621 "please wait until it is finished.",
622 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000623
Chui Tey5d2af632002-05-26 13:36:41 +0000624 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000625 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000626 # The code better not raise an exception!
627 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000628 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000629 return 0
630 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000631 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000632 else:
633 exec code in self.locals
634 return 1
635
David Scherer7aced172000-08-15 01:13:23 +0000636 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000637 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000638 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000639 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000640 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000641 if self.save_warnings_filters is not None:
642 warnings.filters[:] = self.save_warnings_filters
643 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000644 debugger = self.debugger
645 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000646 self.tkconsole.beginexecuting()
647 try:
648 if not debugger and self.rpcclt is not None:
649 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
650 (code,), {})
651 elif debugger:
652 debugger.run(code, self.locals)
653 else:
654 exec code in self.locals
655 except SystemExit:
656 if tkMessageBox.askyesno(
657 "Exit?",
658 "Do you want to exit altogether?",
659 default="yes",
660 master=self.tkconsole.text):
661 raise
662 else:
663 self.showtraceback()
664 except:
David Scherer7aced172000-08-15 01:13:23 +0000665 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000666 finally:
667 if not use_subprocess:
668 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000669
670 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000671 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000672 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000673
David Scherer7aced172000-08-15 01:13:23 +0000674class PyShell(OutputWindow):
675
676 shell_title = "Python Shell"
677
678 # Override classes
679 ColorDelegator = ModifiedColorDelegator
680 UndoDelegator = ModifiedUndoDelegator
681
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000682 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000683 menu_specs = [
684 ("file", "_File"),
685 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000686 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000687 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000688 ("windows", "_Windows"),
689 ("help", "_Help"),
690 ]
David Scherer7aced172000-08-15 01:13:23 +0000691
692 # New classes
693 from IdleHistory import History
694
695 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000696 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000697 ms = self.menu_specs
698 if ms[2][0] != "shell":
699 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000700 self.interp = ModifiedInterpreter(self)
701 if flist is None:
702 root = Tk()
703 fixwordbreaks(root)
704 root.withdraw()
705 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000706 #
David Scherer7aced172000-08-15 01:13:23 +0000707 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000708 #
David Scherer7aced172000-08-15 01:13:23 +0000709 import __builtin__
710 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000711 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000712 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000713 #
David Scherer7aced172000-08-15 01:13:23 +0000714 text = self.text
715 text.configure(wrap="char")
716 text.bind("<<newline-and-indent>>", self.enter_callback)
717 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
718 text.bind("<<interrupt-execution>>", self.cancel_callback)
719 text.bind("<<beginning-of-line>>", self.home_callback)
720 text.bind("<<end-of-file>>", self.eof_callback)
721 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000722 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000723 text.bind("<<open-python-shell>>", self.flist.open_shell)
724 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000725 if use_subprocess:
726 text.bind("<<view-restart>>", self.view_restart_mark)
727 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000728 #
David Scherer7aced172000-08-15 01:13:23 +0000729 self.save_stdout = sys.stdout
730 self.save_stderr = sys.stderr
731 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000732 self.stdout = PseudoFile(self, "stdout")
733 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000734 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000735 if not use_subprocess:
736 sys.stdout = self.stdout
737 sys.stderr = self.stderr
738 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000739 #
David Scherer7aced172000-08-15 01:13:23 +0000740 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000741 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000742 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000743 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000744 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000745
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000746 reading = False
747 executing = False
748 canceled = False
749 endoffile = False
750 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000751
752 def toggle_debugger(self, event=None):
753 if self.executing:
754 tkMessageBox.showerror("Don't debug now",
755 "You can only toggle the debugger when idle",
756 master=self.text)
757 self.set_debugger_indicator()
758 return "break"
759 else:
760 db = self.interp.getdebugger()
761 if db:
762 self.close_debugger()
763 else:
764 self.open_debugger()
765
766 def set_debugger_indicator(self):
767 db = self.interp.getdebugger()
768 self.setvar("<<toggle-debugger>>", not not db)
769
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000770 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000771 pass # All we need is the variable
772
773 def close_debugger(self):
774 db = self.interp.getdebugger()
775 if db:
776 self.interp.setdebugger(None)
777 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000778 if self.interp.rpcclt:
779 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000780 self.resetoutput()
781 self.console.write("[DEBUG OFF]\n")
782 sys.ps1 = ">>> "
783 self.showprompt()
784 self.set_debugger_indicator()
785
786 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000787 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000788 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
789 self)
790 else:
791 dbg_gui = Debugger.Debugger(self)
792 self.interp.setdebugger(dbg_gui)
793 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000794 sys.ps1 = "[DEBUG ON]\n>>> "
795 self.showprompt()
796 self.set_debugger_indicator()
797
David Scherer7aced172000-08-15 01:13:23 +0000798 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000799 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000800 self.resetoutput()
801 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000802
803 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000804 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000805 self.executing = 0
806 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000807 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000808
809 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000810 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000811 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000812 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000813 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000814 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000815 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000816 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000817 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000818 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000819 self.closing = True
820 # Wait for poll_subprocess() rescheduling to stop
821 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000822
823 def close2(self):
824 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000825
826 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000827 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000828 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000829 if use_subprocess:
830 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000831 # Restore std streams
832 sys.stdout = self.save_stdout
833 sys.stderr = self.save_stderr
834 sys.stdin = self.save_stdin
835 # Break cycles
836 self.interp = None
837 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000838 self.flist.pyshell = None
839 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000840 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000841
842 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000843 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000844 return True
David Scherer7aced172000-08-15 01:13:23 +0000845
846 def short_title(self):
847 return self.shell_title
848
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000849 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000850 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000851
David Scherer7aced172000-08-15 01:13:23 +0000852 def begin(self):
853 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000854 if use_subprocess:
855 nosub = ''
856 else:
857 nosub = "==== No Subprocess ===="
858 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000859 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000860 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000861 self.showprompt()
862 import Tkinter
863 Tkinter._default_root = None
864
865 def interact(self):
866 self.begin()
867 self.top.mainloop()
868
869 def readline(self):
870 save = self.reading
871 try:
872 self.reading = 1
873 self.top.mainloop()
874 finally:
875 self.reading = save
876 line = self.text.get("iomark", "end-1c")
877 self.resetoutput()
878 if self.canceled:
879 self.canceled = 0
880 raise KeyboardInterrupt
881 if self.endoffile:
882 self.endoffile = 0
883 return ""
884 return line
885
886 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000887 return True
David Scherer7aced172000-08-15 01:13:23 +0000888
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000889 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000890 try:
891 if self.text.compare("sel.first", "!=", "sel.last"):
892 return # Active selection -- always use default binding
893 except:
894 pass
895 if not (self.executing or self.reading):
896 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000897 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000898 self.showprompt()
899 return "break"
900 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000901 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000902 if self.reading:
903 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000904 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000905 if self.interp.getdebugger():
906 self.interp.restart_subprocess()
907 else:
908 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000909 return "break"
910
911 def eof_callback(self, event):
912 if self.executing and not self.reading:
913 return # Let the default binding (delete next char) take over
914 if not (self.text.compare("iomark", "==", "insert") and
915 self.text.compare("insert", "==", "end-1c")):
916 return # Let the default binding (delete next char) take over
917 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000918 self.resetoutput()
919 self.close()
920 else:
921 self.canceled = 0
922 self.endoffile = 1
923 self.top.quit()
924 return "break"
925
926 def home_callback(self, event):
927 if event.state != 0 and event.keysym == "Home":
928 return # <Modifier-Home>; fall back to class binding
929 if self.text.compare("iomark", "<=", "insert") and \
930 self.text.compare("insert linestart", "<=", "iomark"):
931 self.text.mark_set("insert", "iomark")
932 self.text.tag_remove("sel", "1.0", "end")
933 self.text.see("insert")
934 return "break"
935
936 def linefeed_callback(self, event):
937 # Insert a linefeed without entering anything (still autoindented)
938 if self.reading:
939 self.text.insert("insert", "\n")
940 self.text.see("insert")
941 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000942 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000943 return "break"
944
945 def enter_callback(self, event):
946 if self.executing and not self.reading:
947 return # Let the default binding (insert '\n') take over
948 # If some text is selected, recall the selection
949 # (but only if this before the I/O mark)
950 try:
951 sel = self.text.get("sel.first", "sel.last")
952 if sel:
953 if self.text.compare("sel.last", "<=", "iomark"):
954 self.recall(sel)
955 return "break"
956 except:
957 pass
958 # If we're strictly before the line containing iomark, recall
959 # the current line, less a leading prompt, less leading or
960 # trailing whitespace
961 if self.text.compare("insert", "<", "iomark linestart"):
962 # Check if there's a relevant stdin range -- if so, use it
963 prev = self.text.tag_prevrange("stdin", "insert")
964 if prev and self.text.compare("insert", "<", prev[1]):
965 self.recall(self.text.get(prev[0], prev[1]))
966 return "break"
967 next = self.text.tag_nextrange("stdin", "insert")
968 if next and self.text.compare("insert lineend", ">=", next[0]):
969 self.recall(self.text.get(next[0], next[1]))
970 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000971 # No stdin mark -- just get the current line, less any prompt
972 line = self.text.get("insert linestart", "insert lineend")
973 last_line_of_prompt = sys.ps1.split('\n')[-1]
974 if line.startswith(last_line_of_prompt):
975 line = line[len(last_line_of_prompt):]
976 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000977 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000978 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000979 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000980 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000981 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000982 # If we're in the current input and there's only whitespace
983 # beyond the cursor, erase that whitespace first
984 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000985 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000986 self.text.delete("insert", "end-1c")
987 # If we're in the current input before its last line,
988 # insert a newline right at the insert point
989 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000990 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000991 return "break"
992 # We're in the last line; append a newline and submit it
993 self.text.mark_set("insert", "end-1c")
994 if self.reading:
995 self.text.insert("insert", "\n")
996 self.text.see("insert")
997 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000998 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000999 self.text.tag_add("stdin", "iomark", "end-1c")
1000 self.text.update_idletasks()
1001 if self.reading:
1002 self.top.quit() # Break out of recursive mainloop() in raw_input()
1003 else:
1004 self.runit()
1005 return "break"
1006
1007 def recall(self, s):
1008 if self.history:
1009 self.history.recall(s)
1010
1011 def runit(self):
1012 line = self.text.get("iomark", "end-1c")
1013 # Strip off last newline and surrounding whitespace.
1014 # (To allow you to hit return twice to end a statement.)
1015 i = len(line)
1016 while i > 0 and line[i-1] in " \t":
1017 i = i-1
1018 if i > 0 and line[i-1] == "\n":
1019 i = i-1
1020 while i > 0 and line[i-1] in " \t":
1021 i = i-1
1022 line = line[:i]
1023 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001024
David Scherer7aced172000-08-15 01:13:23 +00001025 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001026 if self.interp.rpcclt:
1027 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001028 try:
1029 sys.last_traceback
1030 except:
1031 tkMessageBox.showerror("No stack trace",
1032 "There is no stack trace yet.\n"
1033 "(sys.last_traceback is not defined)",
1034 master=self.text)
1035 return
1036 from StackViewer import StackBrowser
1037 sv = StackBrowser(self.root, self.flist)
1038
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001039 def view_restart_mark(self, event=None):
1040 self.text.see("iomark")
1041 self.text.see("restart")
1042
1043 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001044 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001045
David Scherer7aced172000-08-15 01:13:23 +00001046 def showprompt(self):
1047 self.resetoutput()
1048 try:
1049 s = str(sys.ps1)
1050 except:
1051 s = ""
1052 self.console.write(s)
1053 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001054 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001055 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001056
1057 def resetoutput(self):
1058 source = self.text.get("iomark", "end-1c")
1059 if self.history:
1060 self.history.history_store(source)
1061 if self.text.get("end-2c") != "\n":
1062 self.text.insert("end-1c", "\n")
1063 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001064 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001065 sys.stdout.softspace = 0
1066
1067 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001068 try:
1069 self.text.mark_gravity("iomark", "right")
1070 OutputWindow.write(self, s, tags, "iomark")
1071 self.text.mark_gravity("iomark", "left")
1072 except:
1073 pass
David Scherer7aced172000-08-15 01:13:23 +00001074 if self.canceled:
1075 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001076 if not use_subprocess:
1077 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001078
1079class PseudoFile:
1080
1081 def __init__(self, shell, tags):
1082 self.shell = shell
1083 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001084 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001085
1086 def write(self, s):
1087 self.shell.write(s, self.tags)
1088
1089 def writelines(self, l):
1090 map(self.write, l)
1091
1092 def flush(self):
1093 pass
1094
1095 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001096 return True
David Scherer7aced172000-08-15 01:13:23 +00001097
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001098
David Scherer7aced172000-08-15 01:13:23 +00001099usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001100
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001101USAGE: idle [-deins] [-t title] [file]*
1102 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1103 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001104
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001105 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001106 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001107
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001108The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001109
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001110 -e open an edit window
1111 -i open a shell window
1112
1113The following options imply -i and will open a shell:
1114
1115 -c cmd run the command in a shell, or
1116 -r file run script from file
1117
1118 -d enable the debugger
1119 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1120 -t title set title of shell window
1121
1122A default edit window will be bypassed when -c, -r, or - are used.
1123
1124[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1125
1126Examples:
1127
1128idle
1129 Open an edit window or shell depending on IDLE's configuration.
1130
1131idle foo.py foobar.py
1132 Edit the files, also open a shell if configured to start with shell.
1133
1134idle -est "Baz" foo.py
1135 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1136 window with the title "Baz".
1137
1138idle -c "import sys; print sys.argv" "foo"
1139 Open a shell window and run the command, passing "-c" in sys.argv[0]
1140 and "foo" in sys.argv[1].
1141
1142idle -d -s -r foo.py "Hello World"
1143 Open a shell window, run a startup script, enable the debugger, and
1144 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1145 sys.argv[1].
1146
1147echo "import sys; print sys.argv" | idle - "foobar"
1148 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1149 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001150"""
1151
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001152def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001153 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001154
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001155 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001156 enable_shell = False
1157 enable_edit = False
1158 debug = False
1159 cmd = None
1160 script = None
1161 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001162 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001163 sys.ps1
1164 except AttributeError:
1165 sys.ps1 = '>>> '
1166 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001167 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001168 except getopt.error, msg:
1169 sys.stderr.write("Error: %s\n" % str(msg))
1170 sys.stderr.write(usage_msg)
1171 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001172 for o, a in opts:
1173 if o == '-c':
1174 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001175 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001176 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001177 debug = True
1178 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001179 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001180 enable_edit = True
1181 if o == '-h':
1182 sys.stdout.write(usage_msg)
1183 sys.exit()
1184 if o == '-i':
1185 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001186 if o == '-n':
1187 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001188 if o == '-r':
1189 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001190 if os.path.isfile(script):
1191 pass
1192 else:
1193 print "No script file: ", script
1194 sys.exit()
1195 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001196 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001197 startup = True
1198 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001199 if o == '-t':
1200 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001201 enable_shell = True
1202 if args and args[0] == '-':
1203 cmd = sys.stdin.read()
1204 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001205 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001206 for i in range(len(sys.path)):
1207 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001208 if args and args[0] == '-':
1209 sys.argv = [''] + args[1:]
1210 elif cmd:
1211 sys.argv = ['-c'] + args
1212 elif script:
1213 sys.argv = [script] + args
1214 elif args:
1215 enable_edit = True
1216 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001217 for filename in args:
1218 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001219 for dir in pathx:
1220 dir = os.path.abspath(dir)
1221 if not dir in sys.path:
1222 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001223 else:
1224 dir = os.getcwd()
1225 if not dir in sys.path:
1226 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001227 # check the IDLE settings configuration (but command line overrides)
1228 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001229 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001230 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001231 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001232 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001233 root = Tk(className="Idle")
1234 fixwordbreaks(root)
1235 root.withdraw()
1236 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001237 if enable_edit:
1238 if not (cmd or script):
1239 for filename in args:
1240 flist.open(filename)
1241 if not args:
1242 flist.new()
1243 if enable_shell:
1244 flist.open_shell()
1245 elif enable_shell:
1246 flist.pyshell = PyShell(flist)
1247 flist.pyshell.begin()
1248 shell = flist.pyshell
1249 # handle remaining options:
1250 if debug:
1251 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001252 if startup:
1253 filename = os.environ.get("IDLESTARTUP") or \
1254 os.environ.get("PYTHONSTARTUP")
1255 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001256 shell.interp.execfile(filename)
1257 if cmd or script:
1258 shell.interp.runcommand("""if 1:
1259 import sys as _sys
1260 _sys.argv = %s
1261 del _sys
1262 \n""" % `sys.argv`)
1263 if cmd:
1264 shell.interp.execsource(cmd)
1265 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001266 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001267 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001268 root.mainloop()
1269 root.destroy()
1270
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001271
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001272def display_port_binding_error():
1273 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001274\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001275
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001276IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1277its Python execution server. IDLE is unable to bind to this port, and so
1278cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001279
1280 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001281 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001282 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001283
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001284Run IDLE with the -n command line switch to start without a subprocess
1285and refer to Help/IDLE Help "Running without a subprocess" for further
1286details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001287"""
David Scherer7aced172000-08-15 01:13:23 +00001288
1289if __name__ == "__main__":
1290 main()