blob: 313c95d1bab5687e86c0c9de76055529352608fb [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
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000019try:
20 from Tkinter import *
21except ImportError:
22 print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
23 "Your Python may not be configured for Tk. **"
24 sys.exit(1)
David Scherer7aced172000-08-15 01:13:23 +000025import tkMessageBox
26
27from EditorWindow import EditorWindow, fixwordbreaks
28from FileList import FileList
29from ColorDelegator import ColorDelegator
30from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000031from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000032from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000033import idlever
34
Chui Tey5d2af632002-05-26 13:36:41 +000035import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000036import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000037import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000038
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000039IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000040LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000041
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000042try:
43 from signal import SIGTERM
44except ImportError:
45 SIGTERM = 15
46
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000047# Override warnings module to write to warning_stream. Initialize to send IDLE
48# internal warnings to the console. ScriptBinding.check_syntax() will
49# temporarily redirect the stream to the shell window to display warnings when
50# checking user's code.
51global warning_stream
52warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000053try:
54 import warnings
55except ImportError:
56 pass
57else:
58 def idle_showwarning(message, category, filename, lineno):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000059 file = warning_stream
60 try:
61 file.write(warnings.formatwarning(message, category, filename, lineno))
62 except IOError:
63 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000064 warnings.showwarning = idle_showwarning
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000065 def idle_formatwarning(message, category, filename, lineno):
66 """Format warnings the IDLE way"""
67 s = "\nWarning (from warnings module):\n"
68 s += ' File \"%s\", line %s\n' % (filename, lineno)
69 line = linecache.getline(filename, lineno).strip()
70 if line:
71 s += " %s\n" % line
72 s += "%s: %s\n>>> " % (category.__name__, message)
73 return s
74 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000075
Kurt B. Kaiser81885592002-11-29 22:10:53 +000076def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077 """Extend linecache.checkcache to preserve the <pyshell#...> entries
78
Kurt B. Kaiser81885592002-11-29 22:10:53 +000079 Rather than repeating the linecache code, patch it to save the pyshell#
80 entries, call the original linecache.checkcache(), and then restore the
81 saved entries. Assigning the orig_checkcache keyword arg freezes its value
82 at definition time to the (original) method linecache.checkcache(), i.e.
83 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000084
85 """
David Scherer7aced172000-08-15 01:13:23 +000086 cache = linecache.cache
87 save = {}
88 for filename in cache.keys():
89 if filename[:1] + filename[-1:] == '<>':
90 save[filename] = cache[filename]
91 orig_checkcache()
92 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000093
Kurt B. Kaiser81885592002-11-29 22:10:53 +000094# Patch linecache.checkcache():
95linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000096
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000097
David Scherer7aced172000-08-15 01:13:23 +000098class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +000099 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000100
David Scherer7aced172000-08-15 01:13:23 +0000101 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000102 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000103 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000104 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000105 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000106 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
107
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000108 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
109 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000110 # whenever a file is changed, restore breakpoints
111 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000112 def filename_changed_hook(old_hook=self.io.filename_change_hook,
113 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000114 self.restore_file_breaks()
115 old_hook()
116 self.io.set_filename_change_hook(filename_changed_hook)
117
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000118 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
119 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000120
Chui Teya2adb0f2002-11-04 22:14:54 +0000121 def set_breakpoint(self, lineno):
122 text = self.text
123 filename = self.io.filename
124 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
125 try:
126 i = self.breakpoints.index(lineno)
127 except ValueError: # only add if missing, i.e. do once
128 self.breakpoints.append(lineno)
129 try: # update the subprocess debugger
130 debug = self.flist.pyshell.interp.debugger
131 debug.set_breakpoint_here(filename, lineno)
132 except: # but debugger may not be active right now....
133 pass
134
David Scherer7aced172000-08-15 01:13:23 +0000135 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000136 text = self.text
137 filename = self.io.filename
138 if not filename:
139 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000140 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000141 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000142 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000143
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000144 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000145 text = self.text
146 filename = self.io.filename
147 if not filename:
148 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000149 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000150 lineno = int(float(text.index("insert")))
151 try:
152 self.breakpoints.remove(lineno)
153 except:
154 pass
155 text.tag_remove("BREAK", "insert linestart",\
156 "insert lineend +1char")
157 try:
158 debug = self.flist.pyshell.interp.debugger
159 debug.clear_breakpoint_here(filename, lineno)
160 except:
161 pass
162
163 def clear_file_breaks(self):
164 if self.breakpoints:
165 text = self.text
166 filename = self.io.filename
167 if not filename:
168 text.bell()
169 return
170 self.breakpoints = []
171 text.tag_remove("BREAK", "1.0", END)
172 try:
173 debug = self.flist.pyshell.interp.debugger
174 debug.clear_file_breaks(filename)
175 except:
176 pass
177
Chui Teya2adb0f2002-11-04 22:14:54 +0000178 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000179 "Save breakpoints when file is saved"
180 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
181 # be run. The breaks are saved at that time. If we introduce
182 # a temporary file save feature the save breaks functionality
183 # needs to be re-verified, since the breaks at the time the
184 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000185 # permanent save of the file. Currently, a break introduced
186 # after a save will be effective, but not persistent.
187 # This is necessary to keep the saved breaks synched with the
188 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000189 #
190 # Breakpoints are set as tagged ranges in the text. Certain
191 # kinds of edits cause these ranges to be deleted: Inserting
192 # or deleting a line just before a breakpoint, and certain
193 # deletions prior to a breakpoint. These issues need to be
194 # investigated and understood. It's not clear if they are
195 # Tk issues or IDLE issues, or whether they can actually
196 # be fixed. Since a modified file has to be saved before it is
197 # run, and since self.breakpoints (from which the subprocess
198 # debugger is loaded) is updated during the save, the visible
199 # breaks stay synched with the subprocess even if one of these
200 # unexpected breakpoint deletions occurs.
201 breaks = self.breakpoints
202 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000203 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000204 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000205 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000206 lines = []
207 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000208 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000210 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000211 self.update_breakpoints()
212 breaks = self.breakpoints
213 if breaks:
214 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000215 new_file.close()
216
217 def restore_file_breaks(self):
218 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000219 filename = self.io.filename
220 if filename is None:
221 return
Chui Tey69371d62002-11-04 23:39:45 +0000222 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000223 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000224 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000226 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000227 for breakpoint_linenumber in breakpoint_linenumbers:
228 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000229
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000230 def update_breakpoints(self):
231 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000232 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000233 ranges = text.tag_ranges("BREAK")
234 linenumber_list = self.ranges_to_linenumbers(ranges)
235 self.breakpoints = linenumber_list
236
237 def ranges_to_linenumbers(self, ranges):
238 lines = []
239 for index in range(0, len(ranges), 2):
240 lineno = int(float(ranges[index]))
241 end = int(float(ranges[index+1]))
242 while lineno < end:
243 lines.append(lineno)
244 lineno += 1
245 return lines
246
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000247# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000248# def saved_change_hook(self):
249# "Extend base method - clear breaks if module is modified"
250# if not self.get_saved():
251# self.clear_file_breaks()
252# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000253
254 def _close(self):
255 "Extend base method - clear breaks when module is closed"
256 self.clear_file_breaks()
257 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
David Scherer7aced172000-08-15 01:13:23 +0000259
260class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000261 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000262
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000263 # override FileList's class variable, instances return PyShellEditorWindow
264 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000265 EditorWindow = PyShellEditorWindow
266
267 pyshell = None
268
269 def open_shell(self, event=None):
270 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000271 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000272 else:
273 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000274 if self.pyshell:
275 if not self.pyshell.begin():
276 return None
David Scherer7aced172000-08-15 01:13:23 +0000277 return self.pyshell
278
279
280class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000281 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000282
Steven M. Gavab77d3432002-03-02 07:16:21 +0000283 def __init__(self):
284 ColorDelegator.__init__(self)
285 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000286
287 def recolorize_main(self):
288 self.tag_remove("TODO", "1.0", "iomark")
289 self.tag_add("SYNC", "1.0", "iomark")
290 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000291
Steven M. Gavab77d3432002-03-02 07:16:21 +0000292 def LoadTagDefs(self):
293 ColorDelegator.LoadTagDefs(self)
294 theme = idleConf.GetOption('main','Theme','name')
295 self.tagdefs.update({
296 "stdin": {'background':None,'foreground':None},
297 "stdout": idleConf.GetHighlight(theme, "stdout"),
298 "stderr": idleConf.GetHighlight(theme, "stderr"),
299 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000300 None: idleConf.GetHighlight(theme, "normal"),
301 })
David Scherer7aced172000-08-15 01:13:23 +0000302
David Scherer7aced172000-08-15 01:13:23 +0000303class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000304 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000305
306 def insert(self, index, chars, tags=None):
307 try:
308 if self.delegate.compare(index, "<", "iomark"):
309 self.delegate.bell()
310 return
311 except TclError:
312 pass
313 UndoDelegator.insert(self, index, chars, tags)
314
315 def delete(self, index1, index2=None):
316 try:
317 if self.delegate.compare(index1, "<", "iomark"):
318 self.delegate.bell()
319 return
320 except TclError:
321 pass
322 UndoDelegator.delete(self, index1, index2)
323
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000324
325class MyRPCClient(rpc.RPCClient):
326
327 def handle_EOF(self):
328 "Override the base class - just re-raise EOFError"
329 raise EOFError
330
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000331
David Scherer7aced172000-08-15 01:13:23 +0000332class ModifiedInterpreter(InteractiveInterpreter):
333
334 def __init__(self, tkconsole):
335 self.tkconsole = tkconsole
336 locals = sys.modules['__main__'].__dict__
337 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000338 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000339 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000340 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000341
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000342 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000343 rpcclt = None
344 rpcpid = None
345
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000346 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000347 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000348 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000349
Tony Lowndsf53dec22002-12-20 04:24:43 +0000350 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000351 w = ['-W' + s for s in sys.warnoptions]
352 # Maybe IDLE is installed and is being accessed via sys.path,
353 # or maybe it's not installed and the idle.py script is being
354 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000355 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
356 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000357 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000358 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000359 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000360 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000361 if sys.platform[:3] == 'win' and ' ' in sys.executable:
362 # handle embedded space in path by quoting the argument
363 decorated_exec = '"%s"' % sys.executable
364 else:
365 decorated_exec = sys.executable
366 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000367
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000368 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000369 # spawning first avoids passing a listening socket to the subprocess
370 self.spawn_subprocess()
371 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000372 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000373 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000374 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000375 time.sleep(i)
376 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000377 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000378 break
379 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000380 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000381 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000382 self.display_port_binding_error()
383 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000384 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000385 self.rpcclt.listening_sock.settimeout(10)
386 try:
387 self.rpcclt.accept()
388 except socket.timeout, err:
389 self.display_no_subprocess_error()
390 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000391 self.rpcclt.register("stdin", self.tkconsole)
392 self.rpcclt.register("stdout", self.tkconsole.stdout)
393 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000394 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000395 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000396 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000397 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000398 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000399 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000400
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000401 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000402 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000403 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000404 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000405 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000406 debug = self.getdebugger()
407 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000408 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000409 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000410 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
411 except:
412 pass
413 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000414 self.rpcclt.close()
415 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000416 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000417 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000418 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000419 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000420 try:
421 self.rpcclt.accept()
422 except socket.timeout, err:
423 self.display_no_subprocess_error()
424 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000425 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000426 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000427 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000428 if was_executing:
429 console.write('\n')
430 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000431 halfbar = ((int(console.width) - 16) // 2) * '='
432 console.write(halfbar + ' RESTART ' + halfbar)
433 console.text.mark_set("restart", "end-1c")
434 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000435 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000436 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000437 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000438 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000439 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000440 # reload remote debugger breakpoints for all PyShellEditWindows
441 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000442 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000443 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000444
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000445 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000446 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000447
448 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000449 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000450
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000451 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000452 try:
453 self.rpcclt.close()
454 except AttributeError: # no socket
455 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000456 self.unix_terminate()
457 self.tkconsole.executing = False
458 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000459
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000460 def unix_terminate(self):
461 "UNIX: make sure subprocess is terminated and collect status"
462 if hasattr(os, 'kill'):
463 try:
464 os.kill(self.rpcpid, SIGTERM)
465 except OSError:
466 # process already terminated:
467 return
468 else:
469 try:
470 os.waitpid(self.rpcpid, 0)
471 except OSError:
472 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000473
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000474 def transfer_path(self):
475 self.runcommand("""if 1:
476 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000477 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000478 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000479 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
480 __builtins__.quit = __builtins__.exit = _msg
481 del _msg
Walter Dörwald70a6b492004-02-12 17:35:32 +0000482 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000483
Chui Tey5d2af632002-05-26 13:36:41 +0000484 active_seq = None
485
486 def poll_subprocess(self):
487 clt = self.rpcclt
488 if clt is None:
489 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000490 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000491 response = clt.pollresponse(self.active_seq, wait=0.05)
492 except (EOFError, IOError, KeyboardInterrupt):
493 # lost connection or subprocess terminated itself, restart
494 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000495 if self.tkconsole.closing:
496 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000497 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000498 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000499 if response:
500 self.tkconsole.resetoutput()
501 self.active_seq = None
502 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000503 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000504 if how == "OK":
505 if what is not None:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000506 print >>console, repr(what)
Chui Tey5d2af632002-05-26 13:36:41 +0000507 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000508 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
509 self.remote_stack_viewer()
510 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000511 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
512 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000513 print >>console, errmsg, what
514 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000515 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000516 # Reschedule myself
517 if not self.tkconsole.closing:
518 self.tkconsole.text.after(self.tkconsole.pollinterval,
519 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000520
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000521 debugger = None
522
523 def setdebugger(self, debugger):
524 self.debugger = debugger
525
526 def getdebugger(self):
527 return self.debugger
528
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000529 def open_remote_stack_viewer(self):
530 """Initiate the remote stack viewer from a separate thread.
531
532 This method is called from the subprocess, and by returning from this
533 method we allow the subprocess to unblock. After a bit the shell
534 requests the subprocess to open the remote stack viewer which returns a
535 static object looking at the last exceptiopn. It is queried through
536 the RPC mechanism.
537
538 """
539 self.tkconsole.text.after(300, self.remote_stack_viewer)
540 return
541
Chui Tey5d2af632002-05-26 13:36:41 +0000542 def remote_stack_viewer(self):
543 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000544 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000545 if oid is None:
546 self.tkconsole.root.bell()
547 return
548 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
549 from TreeWidget import ScrolledCanvas, TreeNode
550 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000551 theme = idleConf.GetOption('main','Theme','name')
552 background = idleConf.GetHighlight(theme, 'normal')['background']
553 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000554 sc.frame.pack(expand=1, fill="both")
555 node = TreeNode(sc.canvas, None, item)
556 node.expand()
557 # XXX Should GC the remote tree when closing the window
558
David Scherer7aced172000-08-15 01:13:23 +0000559 gid = 0
560
561 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000562 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000563 filename = self.stuffsource(source)
564 self.execfile(filename, source)
565
566 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000567 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000568 if source is None:
569 source = open(filename, "r").read()
570 try:
571 code = compile(source, filename, "exec")
572 except (OverflowError, SyntaxError):
573 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000574 tkerr = self.tkconsole.stderr
575 print>>tkerr, '*** Error in script or command!\n'
576 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000577 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000578 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000579 else:
580 self.runcode(code)
581
582 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000583 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000584 filename = self.stuffsource(source)
585 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000586 self.save_warnings_filters = warnings.filters[:]
587 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000588 if isinstance(source, types.UnicodeType):
589 import IOBinding
590 try:
591 source = source.encode(IOBinding.encoding)
592 except UnicodeError:
593 self.tkconsole.resetoutput()
594 self.write("Unsupported characters in input")
595 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000596 try:
597 return InteractiveInterpreter.runsource(self, source, filename)
598 finally:
599 if self.save_warnings_filters is not None:
600 warnings.filters[:] = self.save_warnings_filters
601 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000602
603 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000604 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000605 filename = "<pyshell#%d>" % self.gid
606 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000607 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000608 linecache.cache[filename] = len(source)+1, 0, lines, filename
609 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000610
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000611 def prepend_syspath(self, filename):
612 "Prepend sys.path with file's directory if not already included"
613 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000614 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000615 import sys as _sys
616 from os.path import dirname as _dirname
617 _dir = _dirname(_filename)
618 if not _dir in _sys.path:
619 _sys.path.insert(0, _dir)
620 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000621 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000622
David Scherer7aced172000-08-15 01:13:23 +0000623 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000624 """Extend base class method: Add Colorizing
625
626 Color the offending position instead of printing it and pointing at it
627 with a caret.
628
629 """
David Scherer7aced172000-08-15 01:13:23 +0000630 text = self.tkconsole.text
631 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000632 if stuff:
633 msg, lineno, offset, line = stuff
634 if lineno == 1:
635 pos = "iomark + %d chars" % (offset-1)
636 else:
637 pos = "iomark linestart + %d lines + %d chars" % \
638 (lineno-1, offset-1)
639 text.tag_add("ERROR", pos)
640 text.see(pos)
641 char = text.get(pos)
642 if char and char in IDENTCHARS:
643 text.tag_add("ERROR", pos + " wordstart", pos)
644 self.tkconsole.resetoutput()
645 self.write("SyntaxError: %s\n" % str(msg))
646 else:
David Scherer7aced172000-08-15 01:13:23 +0000647 self.tkconsole.resetoutput()
648 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000649 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000650
651 def unpackerror(self):
652 type, value, tb = sys.exc_info()
653 ok = type is SyntaxError
654 if ok:
655 try:
656 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000657 if not offset:
658 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000659 except:
660 ok = 0
661 if ok:
662 return msg, lineno, offset, line
663 else:
664 return None
665
666 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000667 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000668 self.tkconsole.resetoutput()
669 self.checklinecache()
670 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000671 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
672 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000673
674 def checklinecache(self):
675 c = linecache.cache
676 for key in c.keys():
677 if key[:1] + key[-1:] != "<>":
678 del c[key]
679
Chui Tey5d2af632002-05-26 13:36:41 +0000680 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000681 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000682 # The code better not raise an exception!
683 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000684 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000685 return 0
686 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000687 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000688 else:
689 exec code in self.locals
690 return 1
691
David Scherer7aced172000-08-15 01:13:23 +0000692 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000693 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000694 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000695 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000696 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000697 if self.save_warnings_filters is not None:
698 warnings.filters[:] = self.save_warnings_filters
699 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000700 debugger = self.debugger
701 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000702 self.tkconsole.beginexecuting()
703 try:
704 if not debugger and self.rpcclt is not None:
705 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
706 (code,), {})
707 elif debugger:
708 debugger.run(code, self.locals)
709 else:
710 exec code in self.locals
711 except SystemExit:
712 if tkMessageBox.askyesno(
713 "Exit?",
714 "Do you want to exit altogether?",
715 default="yes",
716 master=self.tkconsole.text):
717 raise
718 else:
719 self.showtraceback()
720 except:
David Scherer7aced172000-08-15 01:13:23 +0000721 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000722 finally:
723 if not use_subprocess:
724 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000725
726 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000727 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000728 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000729
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000730 def display_port_binding_error(self):
731 tkMessageBox.showerror(
732 "Port Binding Error",
733 "IDLE can't bind TCP/IP port 8833, which is necessary to "
734 "communicate with its Python execution server. Either "
735 "no networking is installed on this computer or another "
736 "process (another IDLE?) is using the port. Run IDLE with the -n "
737 "command line switch to start without a subprocess and refer to "
738 "Help/IDLE Help 'Running without a subprocess' for further "
739 "details.",
740 master=self.tkconsole.text)
741
742 def display_no_subprocess_error(self):
743 tkMessageBox.showerror(
744 "Subprocess Startup Error",
745 "IDLE's subprocess didn't make connection. Either IDLE can't "
746 "start a subprocess or personal firewall software is blocking "
747 "the connection.",
748 master=self.tkconsole.text)
749
750 def display_executing_dialog(self):
751 tkMessageBox.showerror(
752 "Already executing",
753 "The Python Shell window is already executing a command; "
754 "please wait until it is finished.",
755 master=self.tkconsole.text)
756
757
David Scherer7aced172000-08-15 01:13:23 +0000758class PyShell(OutputWindow):
759
760 shell_title = "Python Shell"
761
762 # Override classes
763 ColorDelegator = ModifiedColorDelegator
764 UndoDelegator = ModifiedUndoDelegator
765
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000766 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000767 menu_specs = [
768 ("file", "_File"),
769 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000770 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000771 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000772 ("windows", "_Windows"),
773 ("help", "_Help"),
774 ]
David Scherer7aced172000-08-15 01:13:23 +0000775
776 # New classes
777 from IdleHistory import History
778
779 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000780 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000781 ms = self.menu_specs
782 if ms[2][0] != "shell":
783 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000784 self.interp = ModifiedInterpreter(self)
785 if flist is None:
786 root = Tk()
787 fixwordbreaks(root)
788 root.withdraw()
789 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000790 #
David Scherer7aced172000-08-15 01:13:23 +0000791 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000792 #
David Scherer7aced172000-08-15 01:13:23 +0000793 import __builtin__
794 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000795 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000796 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000797 #
David Scherer7aced172000-08-15 01:13:23 +0000798 text = self.text
799 text.configure(wrap="char")
800 text.bind("<<newline-and-indent>>", self.enter_callback)
801 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
802 text.bind("<<interrupt-execution>>", self.cancel_callback)
803 text.bind("<<beginning-of-line>>", self.home_callback)
804 text.bind("<<end-of-file>>", self.eof_callback)
805 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000806 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000807 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000808 if use_subprocess:
809 text.bind("<<view-restart>>", self.view_restart_mark)
810 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000811 #
David Scherer7aced172000-08-15 01:13:23 +0000812 self.save_stdout = sys.stdout
813 self.save_stderr = sys.stderr
814 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000815 import IOBinding
816 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
817 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
818 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000819 if not use_subprocess:
820 sys.stdout = self.stdout
821 sys.stderr = self.stderr
822 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000823 #
David Scherer7aced172000-08-15 01:13:23 +0000824 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000825 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000826 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000827
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000828 def get_standard_extension_names(self):
829 return idleConf.GetExtensions(shell_only=True)
830
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000831 reading = False
832 executing = False
833 canceled = False
834 endoffile = False
835 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000836
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000837 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000838 global warning_stream
839 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000840
841 def get_warning_stream(self):
842 return warning_stream
843
David Scherer7aced172000-08-15 01:13:23 +0000844 def toggle_debugger(self, event=None):
845 if self.executing:
846 tkMessageBox.showerror("Don't debug now",
847 "You can only toggle the debugger when idle",
848 master=self.text)
849 self.set_debugger_indicator()
850 return "break"
851 else:
852 db = self.interp.getdebugger()
853 if db:
854 self.close_debugger()
855 else:
856 self.open_debugger()
857
858 def set_debugger_indicator(self):
859 db = self.interp.getdebugger()
860 self.setvar("<<toggle-debugger>>", not not db)
861
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000862 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000863 pass # All we need is the variable
864
865 def close_debugger(self):
866 db = self.interp.getdebugger()
867 if db:
868 self.interp.setdebugger(None)
869 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000870 if self.interp.rpcclt:
871 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000872 self.resetoutput()
873 self.console.write("[DEBUG OFF]\n")
874 sys.ps1 = ">>> "
875 self.showprompt()
876 self.set_debugger_indicator()
877
878 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000879 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000880 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
881 self)
882 else:
883 dbg_gui = Debugger.Debugger(self)
884 self.interp.setdebugger(dbg_gui)
885 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000886 sys.ps1 = "[DEBUG ON]\n>>> "
887 self.showprompt()
888 self.set_debugger_indicator()
889
David Scherer7aced172000-08-15 01:13:23 +0000890 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000891 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000892 self.resetoutput()
893 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000894
895 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000896 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000897 self.executing = 0
898 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000899 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000900
901 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000902 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000903 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000904 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000905 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000906 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000907 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000908 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000909 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000910 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000911 self.closing = True
912 # Wait for poll_subprocess() rescheduling to stop
913 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000914
915 def close2(self):
916 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000917
918 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000919 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000920 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000921 if use_subprocess:
922 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000923 # Restore std streams
924 sys.stdout = self.save_stdout
925 sys.stderr = self.save_stderr
926 sys.stdin = self.save_stdin
927 # Break cycles
928 self.interp = None
929 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000930 self.flist.pyshell = None
931 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000932 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000933
934 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000935 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000936 return True
David Scherer7aced172000-08-15 01:13:23 +0000937
938 def short_title(self):
939 return self.shell_title
940
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000941 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000942 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000943
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000944 firewallmessage = """
945 ****************************************************************
946 Personal firewall software may warn about the connection IDLE
947 makes to its subprocess using this computer's internal loopback
948 interface. This connection is not visible on any external
949 interface and no data is sent to or received from the Internet.
950 ****************************************************************
951 """
952
David Scherer7aced172000-08-15 01:13:23 +0000953 def begin(self):
954 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000955 if use_subprocess:
956 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000957 client = self.interp.start_subprocess()
958 if not client:
959 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000960 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000961 else:
962 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000963 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000964 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000965 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000966 self.showprompt()
967 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000968 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000969 return True
David Scherer7aced172000-08-15 01:13:23 +0000970
971 def readline(self):
972 save = self.reading
973 try:
974 self.reading = 1
975 self.top.mainloop()
976 finally:
977 self.reading = save
978 line = self.text.get("iomark", "end-1c")
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000979 if isinstance(line, unicode):
980 import IOBinding
981 try:
982 line = line.encode(IOBinding.encoding)
983 except UnicodeError:
984 pass
David Scherer7aced172000-08-15 01:13:23 +0000985 self.resetoutput()
986 if self.canceled:
987 self.canceled = 0
988 raise KeyboardInterrupt
989 if self.endoffile:
990 self.endoffile = 0
991 return ""
992 return line
993
994 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000995 return True
David Scherer7aced172000-08-15 01:13:23 +0000996
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000997 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000998 try:
999 if self.text.compare("sel.first", "!=", "sel.last"):
1000 return # Active selection -- always use default binding
1001 except:
1002 pass
1003 if not (self.executing or self.reading):
1004 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001005 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001006 self.showprompt()
1007 return "break"
1008 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001009 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +00001010 if self.reading:
1011 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001012 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001013 if self.interp.getdebugger():
1014 self.interp.restart_subprocess()
1015 else:
1016 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +00001017 return "break"
1018
1019 def eof_callback(self, event):
1020 if self.executing and not self.reading:
1021 return # Let the default binding (delete next char) take over
1022 if not (self.text.compare("iomark", "==", "insert") and
1023 self.text.compare("insert", "==", "end-1c")):
1024 return # Let the default binding (delete next char) take over
1025 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001026 self.resetoutput()
1027 self.close()
1028 else:
1029 self.canceled = 0
1030 self.endoffile = 1
1031 self.top.quit()
1032 return "break"
1033
1034 def home_callback(self, event):
1035 if event.state != 0 and event.keysym == "Home":
1036 return # <Modifier-Home>; fall back to class binding
1037 if self.text.compare("iomark", "<=", "insert") and \
1038 self.text.compare("insert linestart", "<=", "iomark"):
1039 self.text.mark_set("insert", "iomark")
1040 self.text.tag_remove("sel", "1.0", "end")
1041 self.text.see("insert")
1042 return "break"
1043
1044 def linefeed_callback(self, event):
1045 # Insert a linefeed without entering anything (still autoindented)
1046 if self.reading:
1047 self.text.insert("insert", "\n")
1048 self.text.see("insert")
1049 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001050 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001051 return "break"
1052
1053 def enter_callback(self, event):
1054 if self.executing and not self.reading:
1055 return # Let the default binding (insert '\n') take over
1056 # If some text is selected, recall the selection
1057 # (but only if this before the I/O mark)
1058 try:
1059 sel = self.text.get("sel.first", "sel.last")
1060 if sel:
1061 if self.text.compare("sel.last", "<=", "iomark"):
1062 self.recall(sel)
1063 return "break"
1064 except:
1065 pass
1066 # If we're strictly before the line containing iomark, recall
1067 # the current line, less a leading prompt, less leading or
1068 # trailing whitespace
1069 if self.text.compare("insert", "<", "iomark linestart"):
1070 # Check if there's a relevant stdin range -- if so, use it
1071 prev = self.text.tag_prevrange("stdin", "insert")
1072 if prev and self.text.compare("insert", "<", prev[1]):
1073 self.recall(self.text.get(prev[0], prev[1]))
1074 return "break"
1075 next = self.text.tag_nextrange("stdin", "insert")
1076 if next and self.text.compare("insert lineend", ">=", next[0]):
1077 self.recall(self.text.get(next[0], next[1]))
1078 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001079 # No stdin mark -- just get the current line, less any prompt
1080 line = self.text.get("insert linestart", "insert lineend")
1081 last_line_of_prompt = sys.ps1.split('\n')[-1]
1082 if line.startswith(last_line_of_prompt):
1083 line = line[len(last_line_of_prompt):]
1084 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +00001085 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001086 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001087 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001088 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001089 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001090 # If we're in the current input and there's only whitespace
1091 # beyond the cursor, erase that whitespace first
1092 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001093 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001094 self.text.delete("insert", "end-1c")
1095 # If we're in the current input before its last line,
1096 # insert a newline right at the insert point
1097 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001098 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001099 return "break"
1100 # We're in the last line; append a newline and submit it
1101 self.text.mark_set("insert", "end-1c")
1102 if self.reading:
1103 self.text.insert("insert", "\n")
1104 self.text.see("insert")
1105 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001106 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001107 self.text.tag_add("stdin", "iomark", "end-1c")
1108 self.text.update_idletasks()
1109 if self.reading:
1110 self.top.quit() # Break out of recursive mainloop() in raw_input()
1111 else:
1112 self.runit()
1113 return "break"
1114
1115 def recall(self, s):
1116 if self.history:
1117 self.history.recall(s)
1118
1119 def runit(self):
1120 line = self.text.get("iomark", "end-1c")
1121 # Strip off last newline and surrounding whitespace.
1122 # (To allow you to hit return twice to end a statement.)
1123 i = len(line)
1124 while i > 0 and line[i-1] in " \t":
1125 i = i-1
1126 if i > 0 and line[i-1] == "\n":
1127 i = i-1
1128 while i > 0 and line[i-1] in " \t":
1129 i = i-1
1130 line = line[:i]
1131 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001132
David Scherer7aced172000-08-15 01:13:23 +00001133 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001134 if self.interp.rpcclt:
1135 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001136 try:
1137 sys.last_traceback
1138 except:
1139 tkMessageBox.showerror("No stack trace",
1140 "There is no stack trace yet.\n"
1141 "(sys.last_traceback is not defined)",
1142 master=self.text)
1143 return
1144 from StackViewer import StackBrowser
1145 sv = StackBrowser(self.root, self.flist)
1146
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001147 def view_restart_mark(self, event=None):
1148 self.text.see("iomark")
1149 self.text.see("restart")
1150
1151 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001152 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001153
David Scherer7aced172000-08-15 01:13:23 +00001154 def showprompt(self):
1155 self.resetoutput()
1156 try:
1157 s = str(sys.ps1)
1158 except:
1159 s = ""
1160 self.console.write(s)
1161 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001162 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001163 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001164
1165 def resetoutput(self):
1166 source = self.text.get("iomark", "end-1c")
1167 if self.history:
1168 self.history.history_store(source)
1169 if self.text.get("end-2c") != "\n":
1170 self.text.insert("end-1c", "\n")
1171 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001172 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001173 sys.stdout.softspace = 0
1174
1175 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001176 try:
1177 self.text.mark_gravity("iomark", "right")
1178 OutputWindow.write(self, s, tags, "iomark")
1179 self.text.mark_gravity("iomark", "left")
1180 except:
1181 pass
David Scherer7aced172000-08-15 01:13:23 +00001182 if self.canceled:
1183 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001184 if not use_subprocess:
1185 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001186
1187class PseudoFile:
1188
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001189 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001190 self.shell = shell
1191 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001192 self.softspace = 0
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001193 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001194
1195 def write(self, s):
1196 self.shell.write(s, self.tags)
1197
1198 def writelines(self, l):
1199 map(self.write, l)
1200
1201 def flush(self):
1202 pass
1203
1204 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001205 return True
David Scherer7aced172000-08-15 01:13:23 +00001206
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001207
David Scherer7aced172000-08-15 01:13:23 +00001208usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001209
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001210USAGE: idle [-deins] [-t title] [file]*
1211 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1212 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001213
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001214 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001215 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001216
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001217The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001218
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001219 -e open an edit window
1220 -i open a shell window
1221
1222The following options imply -i and will open a shell:
1223
1224 -c cmd run the command in a shell, or
1225 -r file run script from file
1226
1227 -d enable the debugger
1228 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1229 -t title set title of shell window
1230
1231A default edit window will be bypassed when -c, -r, or - are used.
1232
1233[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1234
1235Examples:
1236
1237idle
1238 Open an edit window or shell depending on IDLE's configuration.
1239
1240idle foo.py foobar.py
1241 Edit the files, also open a shell if configured to start with shell.
1242
1243idle -est "Baz" foo.py
1244 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1245 window with the title "Baz".
1246
1247idle -c "import sys; print sys.argv" "foo"
1248 Open a shell window and run the command, passing "-c" in sys.argv[0]
1249 and "foo" in sys.argv[1].
1250
1251idle -d -s -r foo.py "Hello World"
1252 Open a shell window, run a startup script, enable the debugger, and
1253 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1254 sys.argv[1].
1255
1256echo "import sys; print sys.argv" | idle - "foobar"
1257 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1258 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001259"""
1260
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001261def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001262 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001263
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001264 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001265 enable_shell = False
1266 enable_edit = False
1267 debug = False
1268 cmd = None
1269 script = None
1270 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001271 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001272 sys.ps1
1273 except AttributeError:
1274 sys.ps1 = '>>> '
1275 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001276 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001277 except getopt.error, msg:
1278 sys.stderr.write("Error: %s\n" % str(msg))
1279 sys.stderr.write(usage_msg)
1280 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001281 for o, a in opts:
1282 if o == '-c':
1283 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001284 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001285 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001286 debug = True
1287 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001288 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001289 enable_edit = True
1290 if o == '-h':
1291 sys.stdout.write(usage_msg)
1292 sys.exit()
1293 if o == '-i':
1294 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001295 if o == '-n':
1296 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001297 if o == '-r':
1298 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001299 if os.path.isfile(script):
1300 pass
1301 else:
1302 print "No script file: ", script
1303 sys.exit()
1304 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001305 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001306 startup = True
1307 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001308 if o == '-t':
1309 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001310 enable_shell = True
1311 if args and args[0] == '-':
1312 cmd = sys.stdin.read()
1313 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001314 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001315 for i in range(len(sys.path)):
1316 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001317 if args and args[0] == '-':
1318 sys.argv = [''] + args[1:]
1319 elif cmd:
1320 sys.argv = ['-c'] + args
1321 elif script:
1322 sys.argv = [script] + args
1323 elif args:
1324 enable_edit = True
1325 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001326 for filename in args:
1327 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001328 for dir in pathx:
1329 dir = os.path.abspath(dir)
1330 if not dir in sys.path:
1331 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001332 else:
1333 dir = os.getcwd()
1334 if not dir in sys.path:
1335 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001336 # check the IDLE settings configuration (but command line overrides)
1337 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001338 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001339 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001340 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001341 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001342 root = Tk(className="Idle")
1343 fixwordbreaks(root)
1344 root.withdraw()
1345 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001346 if enable_edit:
1347 if not (cmd or script):
1348 for filename in args:
1349 flist.open(filename)
1350 if not args:
1351 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001352 if enable_shell:
1353 if not flist.open_shell():
1354 return # couldn't open shell
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001355 shell = flist.pyshell
1356 # handle remaining options:
1357 if debug:
1358 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001359 if startup:
1360 filename = os.environ.get("IDLESTARTUP") or \
1361 os.environ.get("PYTHONSTARTUP")
1362 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001363 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001364 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001365 shell.interp.runcommand("""if 1:
1366 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001367 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001368 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001369 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001370 if cmd:
1371 shell.interp.execsource(cmd)
1372 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001373 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001374 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001375 root.mainloop()
1376 root.destroy()
1377
David Scherer7aced172000-08-15 01:13:23 +00001378if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001379 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001380 main()