blob: 70c36fc8a43ae8d3ba5446975445b120ffa7dbca [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
David Scherer7aced172000-08-15 01:13:23 +00006import getopt
7import re
Chui Tey5d2af632002-05-26 13:36:41 +00008import socket
9import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000010import threading
Chui Tey5d2af632002-05-26 13:36:41 +000011import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000012import types
David Scherer7aced172000-08-15 01:13:23 +000013
14import linecache
15from code import InteractiveInterpreter
16
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000017try:
18 from Tkinter import *
19except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000020 print("** IDLE can't import Tkinter. " \
21 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000022 sys.exit(1)
David Scherer7aced172000-08-15 01:13:23 +000023import tkMessageBox
24
Guido van Rossum36e0a922007-07-20 04:05:57 +000025from .EditorWindow import EditorWindow, fixwordbreaks
26from .FileList import FileList
27from .ColorDelegator import ColorDelegator
28from .UndoDelegator import UndoDelegator
29from .OutputWindow import OutputWindow
30from .configHandler import idleConf
31from . import idlever
32from . import rpc
33from . import Debugger
34from . import RemoteDebugger
35from . import macosxSupport
Chui Tey5d2af632002-05-26 13:36:41 +000036
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000037LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000038
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000039try:
40 from signal import SIGTERM
41except ImportError:
42 SIGTERM = 15
43
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000044# Override warnings module to write to warning_stream. Initialize to send IDLE
45# internal warnings to the console. ScriptBinding.check_syntax() will
46# temporarily redirect the stream to the shell window to display warnings when
47# checking user's code.
48global warning_stream
49warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000050try:
51 import warnings
52except ImportError:
53 pass
54else:
55 def idle_showwarning(message, category, filename, lineno):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000056 file = warning_stream
57 try:
58 file.write(warnings.formatwarning(message, category, filename, lineno))
59 except IOError:
60 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000061 warnings.showwarning = idle_showwarning
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000062 def idle_formatwarning(message, category, filename, lineno):
63 """Format warnings the IDLE way"""
64 s = "\nWarning (from warnings module):\n"
65 s += ' File \"%s\", line %s\n' % (filename, lineno)
66 line = linecache.getline(filename, lineno).strip()
67 if line:
68 s += " %s\n" % line
69 s += "%s: %s\n>>> " % (category.__name__, message)
70 return s
71 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000072
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000073def extended_linecache_checkcache(filename=None,
74 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000075 """Extend linecache.checkcache to preserve the <pyshell#...> entries
76
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000077 Rather than repeating the linecache code, patch it to save the
78 <pyshell#...> entries, call the original linecache.checkcache()
79 (which destroys them), and then restore the saved entries.
80
81 orig_checkcache is bound at definition time to the original
82 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000083
84 """
David Scherer7aced172000-08-15 01:13:23 +000085 cache = linecache.cache
86 save = {}
87 for filename in cache.keys():
88 if filename[:1] + filename[-1:] == '<>':
89 save[filename] = cache[filename]
90 orig_checkcache()
91 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000092
Kurt B. Kaiser81885592002-11-29 22:10:53 +000093# Patch linecache.checkcache():
94linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000095
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000096
David Scherer7aced172000-08-15 01:13:23 +000097class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +000098 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000099
David Scherer7aced172000-08-15 01:13:23 +0000100 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000101 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000102 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000103 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000104 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000105 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
106
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000107 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
108 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000109 # whenever a file is changed, restore breakpoints
110 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000111 def filename_changed_hook(old_hook=self.io.filename_change_hook,
112 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000113 self.restore_file_breaks()
114 old_hook()
115 self.io.set_filename_change_hook(filename_changed_hook)
116
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000117 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
118 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000119
Chui Teya2adb0f2002-11-04 22:14:54 +0000120 def set_breakpoint(self, lineno):
121 text = self.text
122 filename = self.io.filename
123 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
124 try:
125 i = self.breakpoints.index(lineno)
126 except ValueError: # only add if missing, i.e. do once
127 self.breakpoints.append(lineno)
128 try: # update the subprocess debugger
129 debug = self.flist.pyshell.interp.debugger
130 debug.set_breakpoint_here(filename, lineno)
131 except: # but debugger may not be active right now....
132 pass
133
David Scherer7aced172000-08-15 01:13:23 +0000134 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000135 text = self.text
136 filename = self.io.filename
137 if not filename:
138 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000139 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000140 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000141 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000142
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000143 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000144 text = self.text
145 filename = self.io.filename
146 if not filename:
147 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000148 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000149 lineno = int(float(text.index("insert")))
150 try:
151 self.breakpoints.remove(lineno)
152 except:
153 pass
154 text.tag_remove("BREAK", "insert linestart",\
155 "insert lineend +1char")
156 try:
157 debug = self.flist.pyshell.interp.debugger
158 debug.clear_breakpoint_here(filename, lineno)
159 except:
160 pass
161
162 def clear_file_breaks(self):
163 if self.breakpoints:
164 text = self.text
165 filename = self.io.filename
166 if not filename:
167 text.bell()
168 return
169 self.breakpoints = []
170 text.tag_remove("BREAK", "1.0", END)
171 try:
172 debug = self.flist.pyshell.interp.debugger
173 debug.clear_file_breaks(filename)
174 except:
175 pass
176
Chui Teya2adb0f2002-11-04 22:14:54 +0000177 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000178 "Save breakpoints when file is saved"
179 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
180 # be run. The breaks are saved at that time. If we introduce
181 # a temporary file save feature the save breaks functionality
182 # needs to be re-verified, since the breaks at the time the
183 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000184 # permanent save of the file. Currently, a break introduced
185 # after a save will be effective, but not persistent.
186 # This is necessary to keep the saved breaks synched with the
187 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000188 #
189 # Breakpoints are set as tagged ranges in the text. Certain
190 # kinds of edits cause these ranges to be deleted: Inserting
191 # or deleting a line just before a breakpoint, and certain
192 # deletions prior to a breakpoint. These issues need to be
193 # investigated and understood. It's not clear if they are
194 # Tk issues or IDLE issues, or whether they can actually
195 # be fixed. Since a modified file has to be saved before it is
196 # run, and since self.breakpoints (from which the subprocess
197 # debugger is loaded) is updated during the save, the visible
198 # breaks stay synched with the subprocess even if one of these
199 # unexpected breakpoint deletions occurs.
200 breaks = self.breakpoints
201 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000202 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000203 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000204 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000205 lines = []
206 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000207 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000208 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 self.update_breakpoints()
211 breaks = self.breakpoints
212 if breaks:
213 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000214 new_file.close()
215
216 def restore_file_breaks(self):
217 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000218 filename = self.io.filename
219 if filename is None:
220 return
Chui Tey69371d62002-11-04 23:39:45 +0000221 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000222 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000223 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000224 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000225 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000226 for breakpoint_linenumber in breakpoint_linenumbers:
227 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000228
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000229 def update_breakpoints(self):
230 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000231 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000232 ranges = text.tag_ranges("BREAK")
233 linenumber_list = self.ranges_to_linenumbers(ranges)
234 self.breakpoints = linenumber_list
235
236 def ranges_to_linenumbers(self, ranges):
237 lines = []
238 for index in range(0, len(ranges), 2):
239 lineno = int(float(ranges[index]))
240 end = int(float(ranges[index+1]))
241 while lineno < end:
242 lines.append(lineno)
243 lineno += 1
244 return lines
245
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000246# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000247# def saved_change_hook(self):
248# "Extend base method - clear breaks if module is modified"
249# if not self.get_saved():
250# self.clear_file_breaks()
251# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000252
253 def _close(self):
254 "Extend base method - clear breaks when module is closed"
255 self.clear_file_breaks()
256 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000257
David Scherer7aced172000-08-15 01:13:23 +0000258
259class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000260 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000261
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000262 # override FileList's class variable, instances return PyShellEditorWindow
263 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000264 EditorWindow = PyShellEditorWindow
265
266 pyshell = None
267
268 def open_shell(self, event=None):
269 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000270 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000271 else:
272 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000273 if self.pyshell:
274 if not self.pyshell.begin():
275 return None
David Scherer7aced172000-08-15 01:13:23 +0000276 return self.pyshell
277
278
279class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000280 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000281
Steven M. Gavab77d3432002-03-02 07:16:21 +0000282 def __init__(self):
283 ColorDelegator.__init__(self)
284 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000285
286 def recolorize_main(self):
287 self.tag_remove("TODO", "1.0", "iomark")
288 self.tag_add("SYNC", "1.0", "iomark")
289 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000290
Steven M. Gavab77d3432002-03-02 07:16:21 +0000291 def LoadTagDefs(self):
292 ColorDelegator.LoadTagDefs(self)
293 theme = idleConf.GetOption('main','Theme','name')
294 self.tagdefs.update({
295 "stdin": {'background':None,'foreground':None},
296 "stdout": idleConf.GetHighlight(theme, "stdout"),
297 "stderr": idleConf.GetHighlight(theme, "stderr"),
298 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000299 None: idleConf.GetHighlight(theme, "normal"),
300 })
David Scherer7aced172000-08-15 01:13:23 +0000301
David Scherer7aced172000-08-15 01:13:23 +0000302class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000303 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000304
305 def insert(self, index, chars, tags=None):
306 try:
307 if self.delegate.compare(index, "<", "iomark"):
308 self.delegate.bell()
309 return
310 except TclError:
311 pass
312 UndoDelegator.insert(self, index, chars, tags)
313
314 def delete(self, index1, index2=None):
315 try:
316 if self.delegate.compare(index1, "<", "iomark"):
317 self.delegate.bell()
318 return
319 except TclError:
320 pass
321 UndoDelegator.delete(self, index1, index2)
322
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000323
324class MyRPCClient(rpc.RPCClient):
325
326 def handle_EOF(self):
327 "Override the base class - just re-raise EOFError"
328 raise EOFError
329
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000330
David Scherer7aced172000-08-15 01:13:23 +0000331class ModifiedInterpreter(InteractiveInterpreter):
332
333 def __init__(self, tkconsole):
334 self.tkconsole = tkconsole
335 locals = sys.modules['__main__'].__dict__
336 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000337 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000338 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000339 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000340
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000341 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000342 rpcclt = None
343 rpcpid = None
344
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000345 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000346 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000347 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000348
Tony Lowndsf53dec22002-12-20 04:24:43 +0000349 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000350 w = ['-W' + s for s in sys.warnoptions]
351 # Maybe IDLE is installed and is being accessed via sys.path,
352 # or maybe it's not installed and the idle.py script is being
353 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000354 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
355 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000356 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000357 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000358 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000359 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000360 if sys.platform[:3] == 'win' and ' ' in sys.executable:
361 # handle embedded space in path by quoting the argument
362 decorated_exec = '"%s"' % sys.executable
363 else:
364 decorated_exec = sys.executable
365 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000366
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000367 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000368 # spawning first avoids passing a listening socket to the subprocess
369 self.spawn_subprocess()
370 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000371 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000372 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000373 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000374 time.sleep(i)
375 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000376 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000377 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000378 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000379 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000380 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000381 self.display_port_binding_error()
382 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000383 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000384 self.rpcclt.listening_sock.settimeout(10)
385 try:
386 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000387 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000388 self.display_no_subprocess_error()
389 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000390 self.rpcclt.register("stdin", self.tkconsole)
391 self.rpcclt.register("stdout", self.tkconsole.stdout)
392 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000393 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000394 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000395 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000396 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000397 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000398 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000399
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000400 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000401 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000402 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000403 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000404 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000405 debug = self.getdebugger()
406 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000407 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000408 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000409 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
410 except:
411 pass
412 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000413 self.rpcclt.close()
414 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000415 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000416 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000417 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000418 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000419 try:
420 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000421 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000422 self.display_no_subprocess_error()
423 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000424 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000425 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000426 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000427 if was_executing:
428 console.write('\n')
429 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000430 halfbar = ((int(console.width) - 16) // 2) * '='
431 console.write(halfbar + ' RESTART ' + halfbar)
432 console.text.mark_set("restart", "end-1c")
433 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000434 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000435 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000436 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000437 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000438 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000439 # reload remote debugger breakpoints for all PyShellEditWindows
440 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000441 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000442 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000443
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000444 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000445 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000446
447 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000448 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000449
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000450 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000451 try:
452 self.rpcclt.close()
453 except AttributeError: # no socket
454 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000455 self.unix_terminate()
456 self.tkconsole.executing = False
457 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000458
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000459 def unix_terminate(self):
460 "UNIX: make sure subprocess is terminated and collect status"
461 if hasattr(os, 'kill'):
462 try:
463 os.kill(self.rpcpid, SIGTERM)
464 except OSError:
465 # process already terminated:
466 return
467 else:
468 try:
469 os.waitpid(self.rpcpid, 0)
470 except OSError:
471 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000472
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000473 def transfer_path(self):
474 self.runcommand("""if 1:
475 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000476 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000477 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000478 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000479
Chui Tey5d2af632002-05-26 13:36:41 +0000480 active_seq = None
481
482 def poll_subprocess(self):
483 clt = self.rpcclt
484 if clt is None:
485 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000486 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000487 response = clt.pollresponse(self.active_seq, wait=0.05)
488 except (EOFError, IOError, KeyboardInterrupt):
489 # lost connection or subprocess terminated itself, restart
490 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000491 if self.tkconsole.closing:
492 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000493 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000494 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000495 if response:
496 self.tkconsole.resetoutput()
497 self.active_seq = None
498 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000499 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000500 if how == "OK":
501 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000502 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000503 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000504 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
505 self.remote_stack_viewer()
506 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000507 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000508 print(errmsg, what, file=sys.__stderr__)
509 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000510 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000511 try:
512 self.tkconsole.endexecuting()
513 except AttributeError: # shell may have closed
514 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000515 # Reschedule myself
516 if not self.tkconsole.closing:
517 self.tkconsole.text.after(self.tkconsole.pollinterval,
518 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000519
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000520 debugger = None
521
522 def setdebugger(self, debugger):
523 self.debugger = debugger
524
525 def getdebugger(self):
526 return self.debugger
527
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000528 def open_remote_stack_viewer(self):
529 """Initiate the remote stack viewer from a separate thread.
530
531 This method is called from the subprocess, and by returning from this
532 method we allow the subprocess to unblock. After a bit the shell
533 requests the subprocess to open the remote stack viewer which returns a
534 static object looking at the last exceptiopn. It is queried through
535 the RPC mechanism.
536
537 """
538 self.tkconsole.text.after(300, self.remote_stack_viewer)
539 return
540
Chui Tey5d2af632002-05-26 13:36:41 +0000541 def remote_stack_viewer(self):
Guido van Rossum36e0a922007-07-20 04:05:57 +0000542 from . import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000543 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000544 if oid is None:
545 self.tkconsole.root.bell()
546 return
547 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Guido van Rossum36e0a922007-07-20 04:05:57 +0000548 from .TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000549 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000550 theme = idleConf.GetOption('main','Theme','name')
551 background = idleConf.GetHighlight(theme, 'normal')['background']
552 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000553 sc.frame.pack(expand=1, fill="both")
554 node = TreeNode(sc.canvas, None, item)
555 node.expand()
556 # XXX Should GC the remote tree when closing the window
557
David Scherer7aced172000-08-15 01:13:23 +0000558 gid = 0
559
560 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000561 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000562 filename = self.stuffsource(source)
563 self.execfile(filename, source)
564
565 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000566 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000567 if source is None:
568 source = open(filename, "r").read()
569 try:
570 code = compile(source, filename, "exec")
571 except (OverflowError, SyntaxError):
572 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000573 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000574 print('*** Error in script or command!\n', file=tkerr)
575 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000576 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000577 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000578 else:
579 self.runcode(code)
580
581 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000582 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000583 filename = self.stuffsource(source)
584 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000585 self.save_warnings_filters = warnings.filters[:]
586 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000587 if isinstance(source, types.UnicodeType):
Guido van Rossum36e0a922007-07-20 04:05:57 +0000588 from . import IOBinding
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000589 try:
590 source = source.encode(IOBinding.encoding)
591 except UnicodeError:
592 self.tkconsole.resetoutput()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000593 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000594 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000595 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000596 # InteractiveInterpreter.runsource() calls its runcode() method,
597 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000598 return InteractiveInterpreter.runsource(self, source, filename)
599 finally:
600 if self.save_warnings_filters is not None:
601 warnings.filters[:] = self.save_warnings_filters
602 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000603
604 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000605 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000606 filename = "<pyshell#%d>" % self.gid
607 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000608 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000609 linecache.cache[filename] = len(source)+1, 0, lines, filename
610 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000611
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000612 def prepend_syspath(self, filename):
613 "Prepend sys.path with file's directory if not already included"
614 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000615 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000616 import sys as _sys
617 from os.path import dirname as _dirname
618 _dir = _dirname(_filename)
619 if not _dir in _sys.path:
620 _sys.path.insert(0, _dir)
621 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000622 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000623
David Scherer7aced172000-08-15 01:13:23 +0000624 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000625 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000626
627 Color the offending position instead of printing it and pointing at it
628 with a caret.
629
630 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000631 tkconsole = self.tkconsole
632 text = tkconsole.text
633 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000634 type, value, tb = sys.exc_info()
Guido van Rossum33d26892007-08-05 15:29:28 +0000635 msg = value.msg or "<no detail available>"
636 lineno = value.lineno or 1
637 offset = value.offset or 0
638 if offset == 0:
639 lineno += 1 #mark end of offending line
640 if lineno == 1:
641 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000642 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000643 pos = "iomark linestart + %d lines + %d chars" % \
644 (lineno-1, offset-1)
645 tkconsole.colorize_syntax_error(text, pos)
646 tkconsole.resetoutput()
647 self.write("SyntaxError: %s\n" % msg)
648 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000649
650 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000651 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000652 self.tkconsole.resetoutput()
653 self.checklinecache()
654 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000655 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
656 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000657
658 def checklinecache(self):
659 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000660 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000661 if key[:1] + key[-1:] != "<>":
662 del c[key]
663
Chui Tey5d2af632002-05-26 13:36:41 +0000664 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000665 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000666 # The code better not raise an exception!
667 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000668 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000669 return 0
670 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000671 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000672 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000673 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000674 return 1
675
David Scherer7aced172000-08-15 01:13:23 +0000676 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000677 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000678 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000679 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000680 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000681 if self.save_warnings_filters is not None:
682 warnings.filters[:] = self.save_warnings_filters
683 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000684 debugger = self.debugger
685 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000686 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000687 if not debugger and self.rpcclt is not None:
688 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
689 (code,), {})
690 elif debugger:
691 debugger.run(code, self.locals)
692 else:
693 exec(code, self.locals)
694 except SystemExit:
695 if not self.tkconsole.closing:
696 if tkMessageBox.askyesno(
697 "Exit?",
698 "Do you want to exit altogether?",
699 default="yes",
700 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000701 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000702 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000703 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000704 else:
705 raise
706 except:
707 if use_subprocess:
708 print("IDLE internal error in runcode()",
709 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000710 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000711 self.tkconsole.endexecuting()
712 else:
713 if self.tkconsole.canceled:
714 self.tkconsole.canceled = False
715 print("KeyboardInterrupt", file=self.tkconsole.stderr)
716 else:
717 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000718 finally:
719 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000720 try:
721 self.tkconsole.endexecuting()
722 except AttributeError: # shell may have closed
723 pass
David Scherer7aced172000-08-15 01:13:23 +0000724
725 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000726 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000727 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000728
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000729 def display_port_binding_error(self):
730 tkMessageBox.showerror(
731 "Port Binding Error",
732 "IDLE can't bind TCP/IP port 8833, which is necessary to "
733 "communicate with its Python execution server. Either "
734 "no networking is installed on this computer or another "
735 "process (another IDLE?) is using the port. Run IDLE with the -n "
736 "command line switch to start without a subprocess and refer to "
737 "Help/IDLE Help 'Running without a subprocess' for further "
738 "details.",
739 master=self.tkconsole.text)
740
741 def display_no_subprocess_error(self):
742 tkMessageBox.showerror(
743 "Subprocess Startup Error",
744 "IDLE's subprocess didn't make connection. Either IDLE can't "
745 "start a subprocess or personal firewall software is blocking "
746 "the connection.",
747 master=self.tkconsole.text)
748
749 def display_executing_dialog(self):
750 tkMessageBox.showerror(
751 "Already executing",
752 "The Python Shell window is already executing a command; "
753 "please wait until it is finished.",
754 master=self.tkconsole.text)
755
756
David Scherer7aced172000-08-15 01:13:23 +0000757class PyShell(OutputWindow):
758
759 shell_title = "Python Shell"
760
761 # Override classes
762 ColorDelegator = ModifiedColorDelegator
763 UndoDelegator = ModifiedUndoDelegator
764
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000765 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000766 menu_specs = [
767 ("file", "_File"),
768 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000769 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000770 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000771 ("windows", "_Windows"),
772 ("help", "_Help"),
773 ]
David Scherer7aced172000-08-15 01:13:23 +0000774
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000775 if macosxSupport.runningAsOSXApp():
776 del menu_specs[-3]
777 menu_specs[-2] = ("windows", "_Window")
778
779
David Scherer7aced172000-08-15 01:13:23 +0000780 # New classes
Guido van Rossum36e0a922007-07-20 04:05:57 +0000781 from .IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000782
783 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000784 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000785 ms = self.menu_specs
786 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000787 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000788 self.interp = ModifiedInterpreter(self)
789 if flist is None:
790 root = Tk()
791 fixwordbreaks(root)
792 root.withdraw()
793 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000794 #
David Scherer7aced172000-08-15 01:13:23 +0000795 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000796 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000797## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
798 self.usetabs = True
799 # indentwidth must be 8 when using tabs. See note in EditorWindow:
800 self.indentwidth = 8
801 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000802 #
David Scherer7aced172000-08-15 01:13:23 +0000803 text = self.text
804 text.configure(wrap="char")
805 text.bind("<<newline-and-indent>>", self.enter_callback)
806 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
807 text.bind("<<interrupt-execution>>", self.cancel_callback)
808 text.bind("<<beginning-of-line>>", self.home_callback)
809 text.bind("<<end-of-file>>", self.eof_callback)
810 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000811 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000812 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000813 if use_subprocess:
814 text.bind("<<view-restart>>", self.view_restart_mark)
815 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000816 #
David Scherer7aced172000-08-15 01:13:23 +0000817 self.save_stdout = sys.stdout
818 self.save_stderr = sys.stderr
819 self.save_stdin = sys.stdin
Guido van Rossum36e0a922007-07-20 04:05:57 +0000820 from . import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000821 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
822 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
823 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000824 if not use_subprocess:
825 sys.stdout = self.stdout
826 sys.stderr = self.stderr
827 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000828 #
David Scherer7aced172000-08-15 01:13:23 +0000829 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000830 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000831 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000832
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000833 def get_standard_extension_names(self):
834 return idleConf.GetExtensions(shell_only=True)
835
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000836 reading = False
837 executing = False
838 canceled = False
839 endoffile = False
840 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000841
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000842 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000843 global warning_stream
844 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000845
846 def get_warning_stream(self):
847 return warning_stream
848
David Scherer7aced172000-08-15 01:13:23 +0000849 def toggle_debugger(self, event=None):
850 if self.executing:
851 tkMessageBox.showerror("Don't debug now",
852 "You can only toggle the debugger when idle",
853 master=self.text)
854 self.set_debugger_indicator()
855 return "break"
856 else:
857 db = self.interp.getdebugger()
858 if db:
859 self.close_debugger()
860 else:
861 self.open_debugger()
862
863 def set_debugger_indicator(self):
864 db = self.interp.getdebugger()
865 self.setvar("<<toggle-debugger>>", not not db)
866
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000867 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000868 pass # All we need is the variable
869
870 def close_debugger(self):
871 db = self.interp.getdebugger()
872 if db:
873 self.interp.setdebugger(None)
874 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000875 if self.interp.rpcclt:
876 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000877 self.resetoutput()
878 self.console.write("[DEBUG OFF]\n")
879 sys.ps1 = ">>> "
880 self.showprompt()
881 self.set_debugger_indicator()
882
883 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000884 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000885 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
886 self)
887 else:
888 dbg_gui = Debugger.Debugger(self)
889 self.interp.setdebugger(dbg_gui)
890 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000891 sys.ps1 = "[DEBUG ON]\n>>> "
892 self.showprompt()
893 self.set_debugger_indicator()
894
David Scherer7aced172000-08-15 01:13:23 +0000895 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000896 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000897 self.resetoutput()
898 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000899
900 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000901 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000902 self.executing = 0
903 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000904 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000905
906 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000907 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000908 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000909 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000910 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000911 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000912 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000913 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000914 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000915 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000916 if self.reading:
917 self.top.quit()
918 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000919 self.closing = True
920 # Wait for poll_subprocess() rescheduling to stop
921 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000922
923 def close2(self):
924 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000925
926 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000927 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000928 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000929 if use_subprocess:
930 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000931 # Restore std streams
932 sys.stdout = self.save_stdout
933 sys.stderr = self.save_stderr
934 sys.stdin = self.save_stdin
935 # Break cycles
936 self.interp = None
937 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000938 self.flist.pyshell = None
939 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000940 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000941
942 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000943 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000944 return True
David Scherer7aced172000-08-15 01:13:23 +0000945
946 def short_title(self):
947 return self.shell_title
948
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000949 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000950 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000951
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000952 firewallmessage = """
953 ****************************************************************
954 Personal firewall software may warn about the connection IDLE
955 makes to its subprocess using this computer's internal loopback
956 interface. This connection is not visible on any external
957 interface and no data is sent to or received from the Internet.
958 ****************************************************************
959 """
960
David Scherer7aced172000-08-15 01:13:23 +0000961 def begin(self):
962 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000963 if use_subprocess:
964 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000965 client = self.interp.start_subprocess()
966 if not client:
967 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000968 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000969 else:
970 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000971 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000972 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000973 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000974 self.showprompt()
975 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000976 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000977 return True
David Scherer7aced172000-08-15 01:13:23 +0000978
979 def readline(self):
980 save = self.reading
981 try:
982 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000983 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +0000984 finally:
985 self.reading = save
986 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000987 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
988 line = "\n"
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000989 if isinstance(line, str):
Guido van Rossum36e0a922007-07-20 04:05:57 +0000990 from . import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000991 try:
992 line = line.encode(IOBinding.encoding)
993 except UnicodeError:
994 pass
David Scherer7aced172000-08-15 01:13:23 +0000995 self.resetoutput()
996 if self.canceled:
997 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000998 if not use_subprocess:
999 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001000 if self.endoffile:
1001 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001002 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001003 return line
1004
1005 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001006 return True
David Scherer7aced172000-08-15 01:13:23 +00001007
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001008 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001009 try:
1010 if self.text.compare("sel.first", "!=", "sel.last"):
1011 return # Active selection -- always use default binding
1012 except:
1013 pass
1014 if not (self.executing or self.reading):
1015 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001016 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001017 self.showprompt()
1018 return "break"
1019 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001020 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001021 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001022 if self.interp.getdebugger():
1023 self.interp.restart_subprocess()
1024 else:
1025 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001026 if self.reading:
1027 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001028 return "break"
1029
1030 def eof_callback(self, event):
1031 if self.executing and not self.reading:
1032 return # Let the default binding (delete next char) take over
1033 if not (self.text.compare("iomark", "==", "insert") and
1034 self.text.compare("insert", "==", "end-1c")):
1035 return # Let the default binding (delete next char) take over
1036 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001037 self.resetoutput()
1038 self.close()
1039 else:
1040 self.canceled = 0
1041 self.endoffile = 1
1042 self.top.quit()
1043 return "break"
1044
1045 def home_callback(self, event):
1046 if event.state != 0 and event.keysym == "Home":
1047 return # <Modifier-Home>; fall back to class binding
1048 if self.text.compare("iomark", "<=", "insert") and \
1049 self.text.compare("insert linestart", "<=", "iomark"):
1050 self.text.mark_set("insert", "iomark")
1051 self.text.tag_remove("sel", "1.0", "end")
1052 self.text.see("insert")
1053 return "break"
1054
1055 def linefeed_callback(self, event):
1056 # Insert a linefeed without entering anything (still autoindented)
1057 if self.reading:
1058 self.text.insert("insert", "\n")
1059 self.text.see("insert")
1060 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001061 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001062 return "break"
1063
1064 def enter_callback(self, event):
1065 if self.executing and not self.reading:
1066 return # Let the default binding (insert '\n') take over
1067 # If some text is selected, recall the selection
1068 # (but only if this before the I/O mark)
1069 try:
1070 sel = self.text.get("sel.first", "sel.last")
1071 if sel:
1072 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001073 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001074 return "break"
1075 except:
1076 pass
1077 # If we're strictly before the line containing iomark, recall
1078 # the current line, less a leading prompt, less leading or
1079 # trailing whitespace
1080 if self.text.compare("insert", "<", "iomark linestart"):
1081 # Check if there's a relevant stdin range -- if so, use it
1082 prev = self.text.tag_prevrange("stdin", "insert")
1083 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001084 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001085 return "break"
1086 next = self.text.tag_nextrange("stdin", "insert")
1087 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001088 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001089 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001090 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001091 indices = self.text.tag_nextrange("console", "insert linestart")
1092 if indices and \
1093 self.text.compare(indices[0], "<=", "insert linestart"):
1094 self.recall(self.text.get(indices[1], "insert lineend"), event)
1095 else:
1096 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001097 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001098 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001099 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001100 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001101 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001102 # If we're in the current input and there's only whitespace
1103 # beyond the cursor, erase that whitespace first
1104 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001105 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001106 self.text.delete("insert", "end-1c")
1107 # If we're in the current input before its last line,
1108 # insert a newline right at the insert point
1109 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001110 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001111 return "break"
1112 # We're in the last line; append a newline and submit it
1113 self.text.mark_set("insert", "end-1c")
1114 if self.reading:
1115 self.text.insert("insert", "\n")
1116 self.text.see("insert")
1117 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001118 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001119 self.text.tag_add("stdin", "iomark", "end-1c")
1120 self.text.update_idletasks()
1121 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001122 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001123 else:
1124 self.runit()
1125 return "break"
1126
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001127 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001128 # remove leading and trailing empty or whitespace lines
1129 s = re.sub(r'^\s*\n', '' , s)
1130 s = re.sub(r'\n\s*$', '', s)
1131 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001132 self.text.undo_block_start()
1133 try:
1134 self.text.tag_remove("sel", "1.0", "end")
1135 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001136 prefix = self.text.get("insert linestart", "insert")
1137 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001138 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001139 prefix = self.text.get("insert linestart", "insert")
1140 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001141 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001142 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1143 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001144 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001145 if line.startswith(orig_base_indent):
1146 # replace orig base indentation with new indentation
1147 line = new_base_indent + line[len(orig_base_indent):]
1148 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001149 finally:
1150 self.text.see("insert")
1151 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001152
1153 def runit(self):
1154 line = self.text.get("iomark", "end-1c")
1155 # Strip off last newline and surrounding whitespace.
1156 # (To allow you to hit return twice to end a statement.)
1157 i = len(line)
1158 while i > 0 and line[i-1] in " \t":
1159 i = i-1
1160 if i > 0 and line[i-1] == "\n":
1161 i = i-1
1162 while i > 0 and line[i-1] in " \t":
1163 i = i-1
1164 line = line[:i]
1165 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001166
David Scherer7aced172000-08-15 01:13:23 +00001167 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001168 if self.interp.rpcclt:
1169 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001170 try:
1171 sys.last_traceback
1172 except:
1173 tkMessageBox.showerror("No stack trace",
1174 "There is no stack trace yet.\n"
1175 "(sys.last_traceback is not defined)",
1176 master=self.text)
1177 return
Guido van Rossum36e0a922007-07-20 04:05:57 +00001178 from .StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001179 sv = StackBrowser(self.root, self.flist)
1180
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001181 def view_restart_mark(self, event=None):
1182 self.text.see("iomark")
1183 self.text.see("restart")
1184
1185 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001186 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001187
David Scherer7aced172000-08-15 01:13:23 +00001188 def showprompt(self):
1189 self.resetoutput()
1190 try:
1191 s = str(sys.ps1)
1192 except:
1193 s = ""
1194 self.console.write(s)
1195 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001196 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001197 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001198
1199 def resetoutput(self):
1200 source = self.text.get("iomark", "end-1c")
1201 if self.history:
1202 self.history.history_store(source)
1203 if self.text.get("end-2c") != "\n":
1204 self.text.insert("end-1c", "\n")
1205 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001206 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001207
1208 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001209 try:
1210 self.text.mark_gravity("iomark", "right")
1211 OutputWindow.write(self, s, tags, "iomark")
1212 self.text.mark_gravity("iomark", "left")
1213 except:
1214 pass
David Scherer7aced172000-08-15 01:13:23 +00001215 if self.canceled:
1216 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001217 if not use_subprocess:
1218 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001219
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001220class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001221
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001222 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001223 self.shell = shell
1224 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001225 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001226
1227 def write(self, s):
1228 self.shell.write(s, self.tags)
1229
1230 def writelines(self, l):
1231 map(self.write, l)
1232
1233 def flush(self):
1234 pass
1235
1236 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001237 return True
David Scherer7aced172000-08-15 01:13:23 +00001238
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001239
David Scherer7aced172000-08-15 01:13:23 +00001240usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001241
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001242USAGE: idle [-deins] [-t title] [file]*
1243 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1244 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001245
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001246 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001247 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001248
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001249The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001250
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001251 -e open an edit window
1252 -i open a shell window
1253
1254The following options imply -i and will open a shell:
1255
1256 -c cmd run the command in a shell, or
1257 -r file run script from file
1258
1259 -d enable the debugger
1260 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1261 -t title set title of shell window
1262
1263A default edit window will be bypassed when -c, -r, or - are used.
1264
1265[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1266
1267Examples:
1268
1269idle
1270 Open an edit window or shell depending on IDLE's configuration.
1271
1272idle foo.py foobar.py
1273 Edit the files, also open a shell if configured to start with shell.
1274
1275idle -est "Baz" foo.py
1276 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1277 window with the title "Baz".
1278
1279idle -c "import sys; print sys.argv" "foo"
1280 Open a shell window and run the command, passing "-c" in sys.argv[0]
1281 and "foo" in sys.argv[1].
1282
1283idle -d -s -r foo.py "Hello World"
1284 Open a shell window, run a startup script, enable the debugger, and
1285 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1286 sys.argv[1].
1287
1288echo "import sys; print sys.argv" | idle - "foobar"
1289 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1290 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001291"""
1292
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001293def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001294 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001295
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001296 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001297 enable_shell = False
1298 enable_edit = False
1299 debug = False
1300 cmd = None
1301 script = None
1302 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001303 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001304 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001305 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001306 sys.stderr.write("Error: %s\n" % str(msg))
1307 sys.stderr.write(usage_msg)
1308 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001309 for o, a in opts:
1310 if o == '-c':
1311 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001312 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001313 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001314 debug = True
1315 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001316 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001317 enable_edit = True
1318 if o == '-h':
1319 sys.stdout.write(usage_msg)
1320 sys.exit()
1321 if o == '-i':
1322 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001323 if o == '-n':
1324 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001325 if o == '-r':
1326 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001327 if os.path.isfile(script):
1328 pass
1329 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001330 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001331 sys.exit()
1332 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001333 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001334 startup = True
1335 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001336 if o == '-t':
1337 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001338 enable_shell = True
1339 if args and args[0] == '-':
1340 cmd = sys.stdin.read()
1341 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001342 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001343 for i in range(len(sys.path)):
1344 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001345 if args and args[0] == '-':
1346 sys.argv = [''] + args[1:]
1347 elif cmd:
1348 sys.argv = ['-c'] + args
1349 elif script:
1350 sys.argv = [script] + args
1351 elif args:
1352 enable_edit = True
1353 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001354 for filename in args:
1355 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001356 for dir in pathx:
1357 dir = os.path.abspath(dir)
1358 if not dir in sys.path:
1359 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001360 else:
1361 dir = os.getcwd()
1362 if not dir in sys.path:
1363 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 # check the IDLE settings configuration (but command line overrides)
1365 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001366 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001367 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001368 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001369 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001370 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001371
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001372 fixwordbreaks(root)
1373 root.withdraw()
1374 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001375 macosxSupport.setupApp(root, flist)
1376
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001377 if enable_edit:
1378 if not (cmd or script):
1379 for filename in args:
1380 flist.open(filename)
1381 if not args:
1382 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001383 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001384 shell = flist.open_shell()
1385 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001386 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001387
1388 if macosxSupport.runningAsOSXApp() and flist.dict:
1389 # On OSX: when the user has double-clicked on a file that causes
1390 # IDLE to be launched the shell window will open just in front of
1391 # the file she wants to see. Lower the interpreter window when
1392 # there are open files.
1393 shell.top.lower()
1394
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001395 shell = flist.pyshell
1396 # handle remaining options:
1397 if debug:
1398 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001399 if startup:
1400 filename = os.environ.get("IDLESTARTUP") or \
1401 os.environ.get("PYTHONSTARTUP")
1402 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001403 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001404 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001405 shell.interp.runcommand("""if 1:
1406 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001407 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001408 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001409 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001410 if cmd:
1411 shell.interp.execsource(cmd)
1412 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001413 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001414 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001415
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001416 root.mainloop()
1417 root.destroy()
1418
David Scherer7aced172000-08-15 01:13:23 +00001419if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001420 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001421 main()