blob: a7fd928ca29ff57aa4e66486974882c303fd201b [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:
Georg Brandl14fc4272008-05-17 18:39:55 +000018 from tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000019except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000020 print("** IDLE can't import Tkinter. " \
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000021 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000022 sys.exit(1)
Georg Brandl14fc4272008-05-17 18:39:55 +000023import tkinter.messagebox as tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000024
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000025from idlelib.EditorWindow import EditorWindow, fixwordbreaks
26from idlelib.FileList import FileList
27from idlelib.ColorDelegator import ColorDelegator
28from idlelib.UndoDelegator import UndoDelegator
29from idlelib.OutputWindow import OutputWindow
30from idlelib.configHandler import idleConf
31from idlelib import idlever
32from idlelib import rpc
33from idlelib import Debugger
34from idlelib import RemoteDebugger
35from idlelib 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 = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +000087 for filename in cache:
David Scherer7aced172000-08-15 01:13:23 +000088 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 })
David Scherer7aced172000-08-15 01:13:23 +0000300
David Scherer7aced172000-08-15 01:13:23 +0000301class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000302 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000303
304 def insert(self, index, chars, tags=None):
305 try:
306 if self.delegate.compare(index, "<", "iomark"):
307 self.delegate.bell()
308 return
309 except TclError:
310 pass
311 UndoDelegator.insert(self, index, chars, tags)
312
313 def delete(self, index1, index2=None):
314 try:
315 if self.delegate.compare(index1, "<", "iomark"):
316 self.delegate.bell()
317 return
318 except TclError:
319 pass
320 UndoDelegator.delete(self, index1, index2)
321
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000322
323class MyRPCClient(rpc.RPCClient):
324
325 def handle_EOF(self):
326 "Override the base class - just re-raise EOFError"
327 raise EOFError
328
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000329
David Scherer7aced172000-08-15 01:13:23 +0000330class ModifiedInterpreter(InteractiveInterpreter):
331
332 def __init__(self, tkconsole):
333 self.tkconsole = tkconsole
334 locals = sys.modules['__main__'].__dict__
335 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000336 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000337 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000338 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000339
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000340 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000341 rpcclt = None
342 rpcpid = None
343
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000344 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000345 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000346 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000347
Tony Lowndsf53dec22002-12-20 04:24:43 +0000348 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000349 w = ['-W' + s for s in sys.warnoptions]
350 # Maybe IDLE is installed and is being accessed via sys.path,
351 # or maybe it's not installed and the idle.py script is being
352 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000353 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
354 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000355 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000356 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000357 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000358 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000359 if sys.platform[:3] == 'win' and ' ' in sys.executable:
360 # handle embedded space in path by quoting the argument
361 decorated_exec = '"%s"' % sys.executable
362 else:
363 decorated_exec = sys.executable
364 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000365
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000366 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000367 # spawning first avoids passing a listening socket to the subprocess
368 self.spawn_subprocess()
369 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000370 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000371 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000372 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000373 time.sleep(i)
374 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000375 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000376 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000377 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000378 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000379 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000380 self.display_port_binding_error()
381 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000382 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000383 self.rpcclt.listening_sock.settimeout(10)
384 try:
385 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000386 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000387 self.display_no_subprocess_error()
388 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000389 self.rpcclt.register("stdin", self.tkconsole)
390 self.rpcclt.register("stdout", self.tkconsole.stdout)
391 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000392 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000393 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000394 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000395 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000396 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000397 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000398
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000399 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000400 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000401 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000402 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000403 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000404 debug = self.getdebugger()
405 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000406 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000407 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000408 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
409 except:
410 pass
411 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000412 self.rpcclt.close()
413 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000414 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000415 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000416 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000417 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000418 try:
419 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000420 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000421 self.display_no_subprocess_error()
422 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000423 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000424 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000425 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000426 if was_executing:
427 console.write('\n')
428 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000429 halfbar = ((int(console.width) - 16) // 2) * '='
430 console.write(halfbar + ' RESTART ' + halfbar)
431 console.text.mark_set("restart", "end-1c")
432 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000433 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000434 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000435 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000436 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000437 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000438 # reload remote debugger breakpoints for all PyShellEditWindows
439 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000440 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000441 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000442
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000444 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000445
446 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000447 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000448
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000449 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000450 try:
451 self.rpcclt.close()
452 except AttributeError: # no socket
453 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000454 self.unix_terminate()
455 self.tkconsole.executing = False
456 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000457
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000458 def unix_terminate(self):
459 "UNIX: make sure subprocess is terminated and collect status"
460 if hasattr(os, 'kill'):
461 try:
462 os.kill(self.rpcpid, SIGTERM)
463 except OSError:
464 # process already terminated:
465 return
466 else:
467 try:
468 os.waitpid(self.rpcpid, 0)
469 except OSError:
470 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000471
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000472 def transfer_path(self):
473 self.runcommand("""if 1:
474 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000475 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000476 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000477 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000478
Chui Tey5d2af632002-05-26 13:36:41 +0000479 active_seq = None
480
481 def poll_subprocess(self):
482 clt = self.rpcclt
483 if clt is None:
484 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000485 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000486 response = clt.pollresponse(self.active_seq, wait=0.05)
487 except (EOFError, IOError, KeyboardInterrupt):
488 # lost connection or subprocess terminated itself, restart
489 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000490 if self.tkconsole.closing:
491 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000492 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000493 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000494 if response:
495 self.tkconsole.resetoutput()
496 self.active_seq = None
497 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000498 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000499 if how == "OK":
500 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000501 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000502 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000503 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
504 self.remote_stack_viewer()
505 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000506 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000507 print(errmsg, what, file=sys.__stderr__)
508 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000509 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000510 try:
511 self.tkconsole.endexecuting()
512 except AttributeError: # shell may have closed
513 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000514 # Reschedule myself
515 if not self.tkconsole.closing:
516 self.tkconsole.text.after(self.tkconsole.pollinterval,
517 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000518
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000519 debugger = None
520
521 def setdebugger(self, debugger):
522 self.debugger = debugger
523
524 def getdebugger(self):
525 return self.debugger
526
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000527 def open_remote_stack_viewer(self):
528 """Initiate the remote stack viewer from a separate thread.
529
530 This method is called from the subprocess, and by returning from this
531 method we allow the subprocess to unblock. After a bit the shell
532 requests the subprocess to open the remote stack viewer which returns a
533 static object looking at the last exceptiopn. It is queried through
534 the RPC mechanism.
535
536 """
537 self.tkconsole.text.after(300, self.remote_stack_viewer)
538 return
539
Chui Tey5d2af632002-05-26 13:36:41 +0000540 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000541 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000542 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000543 if oid is None:
544 self.tkconsole.root.bell()
545 return
546 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000547 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000548 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000549 theme = idleConf.GetOption('main','Theme','name')
550 background = idleConf.GetHighlight(theme, 'normal')['background']
551 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000552 sc.frame.pack(expand=1, fill="both")
553 node = TreeNode(sc.canvas, None, item)
554 node.expand()
555 # XXX Should GC the remote tree when closing the window
556
David Scherer7aced172000-08-15 01:13:23 +0000557 gid = 0
558
559 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000560 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000561 filename = self.stuffsource(source)
562 self.execfile(filename, source)
563
564 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000565 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000566 if source is None:
567 source = open(filename, "r").read()
568 try:
569 code = compile(source, filename, "exec")
570 except (OverflowError, SyntaxError):
571 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000572 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000573 print('*** Error in script or command!\n', file=tkerr)
574 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000575 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000576 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000577 else:
578 self.runcode(code)
579
580 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000581 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000582 filename = self.stuffsource(source)
583 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000584 self.save_warnings_filters = warnings.filters[:]
585 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000586 # at the moment, InteractiveInterpreter expects str
587 assert isinstance(source, str)
588 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000589 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000590 # try:
591 # source = source.encode(IOBinding.encoding)
592 # except UnicodeError:
593 # self.tkconsole.resetoutput()
594 # self.write("Unsupported characters in input\n")
595 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000596 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000597 # InteractiveInterpreter.runsource() calls its runcode() method,
598 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000599 return InteractiveInterpreter.runsource(self, source, filename)
600 finally:
601 if self.save_warnings_filters is not None:
602 warnings.filters[:] = self.save_warnings_filters
603 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000604
605 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000606 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000607 filename = "<pyshell#%d>" % self.gid
608 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000609 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000610 linecache.cache[filename] = len(source)+1, 0, lines, filename
611 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000612
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000613 def prepend_syspath(self, filename):
614 "Prepend sys.path with file's directory if not already included"
615 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000616 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000617 import sys as _sys
618 from os.path import dirname as _dirname
619 _dir = _dirname(_filename)
620 if not _dir in _sys.path:
621 _sys.path.insert(0, _dir)
622 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000623 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000624
David Scherer7aced172000-08-15 01:13:23 +0000625 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000626 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000627
628 Color the offending position instead of printing it and pointing at it
629 with a caret.
630
631 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000632 tkconsole = self.tkconsole
633 text = tkconsole.text
634 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000635 type, value, tb = sys.exc_info()
Guido van Rossum33d26892007-08-05 15:29:28 +0000636 msg = value.msg or "<no detail available>"
637 lineno = value.lineno or 1
638 offset = value.offset or 0
639 if offset == 0:
640 lineno += 1 #mark end of offending line
641 if lineno == 1:
642 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000643 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000644 pos = "iomark linestart + %d lines + %d chars" % \
645 (lineno-1, offset-1)
646 tkconsole.colorize_syntax_error(text, pos)
647 tkconsole.resetoutput()
648 self.write("SyntaxError: %s\n" % msg)
649 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000650
651 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000652 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000653 self.tkconsole.resetoutput()
654 self.checklinecache()
655 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000656 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
657 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000658
659 def checklinecache(self):
660 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000661 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000662 if key[:1] + key[-1:] != "<>":
663 del c[key]
664
Chui Tey5d2af632002-05-26 13:36:41 +0000665 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000666 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000667 # The code better not raise an exception!
668 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000669 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000670 return 0
671 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000672 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000673 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000674 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000675 return 1
676
David Scherer7aced172000-08-15 01:13:23 +0000677 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000678 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000679 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000680 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000681 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000682 if self.save_warnings_filters is not None:
683 warnings.filters[:] = self.save_warnings_filters
684 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000685 debugger = self.debugger
686 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000687 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000688 if not debugger and self.rpcclt is not None:
689 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
690 (code,), {})
691 elif debugger:
692 debugger.run(code, self.locals)
693 else:
694 exec(code, self.locals)
695 except SystemExit:
696 if not self.tkconsole.closing:
697 if tkMessageBox.askyesno(
698 "Exit?",
699 "Do you want to exit altogether?",
700 default="yes",
701 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000702 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000703 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000704 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000705 else:
706 raise
707 except:
708 if use_subprocess:
709 print("IDLE internal error in runcode()",
710 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000711 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000712 self.tkconsole.endexecuting()
713 else:
714 if self.tkconsole.canceled:
715 self.tkconsole.canceled = False
716 print("KeyboardInterrupt", file=self.tkconsole.stderr)
717 else:
718 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000719 finally:
720 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000721 try:
722 self.tkconsole.endexecuting()
723 except AttributeError: # shell may have closed
724 pass
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
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000776 if macosxSupport.runningAsOSXApp():
777 del menu_specs[-3]
778 menu_specs[-2] = ("windows", "_Window")
779
780
David Scherer7aced172000-08-15 01:13:23 +0000781 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000782 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000783
784 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000785 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000786 ms = self.menu_specs
787 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000788 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000789 self.interp = ModifiedInterpreter(self)
790 if flist is None:
791 root = Tk()
792 fixwordbreaks(root)
793 root.withdraw()
794 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000795 #
David Scherer7aced172000-08-15 01:13:23 +0000796 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000797 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000798## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
799 self.usetabs = True
800 # indentwidth must be 8 when using tabs. See note in EditorWindow:
801 self.indentwidth = 8
802 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000803 #
David Scherer7aced172000-08-15 01:13:23 +0000804 text = self.text
805 text.configure(wrap="char")
806 text.bind("<<newline-and-indent>>", self.enter_callback)
807 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
808 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000809 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. Kaiser8a78cad2007-12-13 03:38:16 +0000813 self.color = color = self.ColorDelegator()
814 self.per.insertfilter(color)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000815 if use_subprocess:
816 text.bind("<<view-restart>>", self.view_restart_mark)
817 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000818 #
David Scherer7aced172000-08-15 01:13:23 +0000819 self.save_stdout = sys.stdout
820 self.save_stderr = sys.stderr
821 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000822 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000823 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
824 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
825 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000826 if not use_subprocess:
827 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000828 sys.stderr = self.stderr
Chui Tey5d2af632002-05-26 13:36:41 +0000829 sys.stdin = self
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000830 try:
831 # page help() text to shell.
832 import pydoc # import must be done here to capture i/o rebinding.
833 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
834 pydoc.pager = pydoc.plainpager
835 except:
836 sys.stderr = sys.__stderr__
837 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000838 #
David Scherer7aced172000-08-15 01:13:23 +0000839 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000840 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000841 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000842
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000843 def get_standard_extension_names(self):
844 return idleConf.GetExtensions(shell_only=True)
845
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000846 reading = False
847 executing = False
848 canceled = False
849 endoffile = False
850 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000851
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000852 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000853 global warning_stream
854 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000855
856 def get_warning_stream(self):
857 return warning_stream
858
David Scherer7aced172000-08-15 01:13:23 +0000859 def toggle_debugger(self, event=None):
860 if self.executing:
861 tkMessageBox.showerror("Don't debug now",
862 "You can only toggle the debugger when idle",
863 master=self.text)
864 self.set_debugger_indicator()
865 return "break"
866 else:
867 db = self.interp.getdebugger()
868 if db:
869 self.close_debugger()
870 else:
871 self.open_debugger()
872
873 def set_debugger_indicator(self):
874 db = self.interp.getdebugger()
875 self.setvar("<<toggle-debugger>>", not not db)
876
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000877 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000878 pass # All we need is the variable
879
880 def close_debugger(self):
881 db = self.interp.getdebugger()
882 if db:
883 self.interp.setdebugger(None)
884 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000885 if self.interp.rpcclt:
886 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000887 self.resetoutput()
888 self.console.write("[DEBUG OFF]\n")
889 sys.ps1 = ">>> "
890 self.showprompt()
891 self.set_debugger_indicator()
892
893 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000894 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000895 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
896 self)
897 else:
898 dbg_gui = Debugger.Debugger(self)
899 self.interp.setdebugger(dbg_gui)
900 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000901 sys.ps1 = "[DEBUG ON]\n>>> "
902 self.showprompt()
903 self.set_debugger_indicator()
904
David Scherer7aced172000-08-15 01:13:23 +0000905 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000906 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000907 self.resetoutput()
908 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000909
910 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000911 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000912 self.executing = 0
913 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000914 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000915
916 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000917 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000918 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000919 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000920 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000921 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000922 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000923 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000924 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000925 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000926 if self.reading:
927 self.top.quit()
928 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000929 self.closing = True
930 # Wait for poll_subprocess() rescheduling to stop
931 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000932
933 def close2(self):
934 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000935
936 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000937 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000938 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000939 if use_subprocess:
940 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000941 # Restore std streams
942 sys.stdout = self.save_stdout
943 sys.stderr = self.save_stderr
944 sys.stdin = self.save_stdin
945 # Break cycles
946 self.interp = None
947 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000948 self.flist.pyshell = None
949 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000950 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000951
952 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000953 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000954 return True
David Scherer7aced172000-08-15 01:13:23 +0000955
956 def short_title(self):
957 return self.shell_title
958
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000959 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000960 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000961
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000962 firewallmessage = """
963 ****************************************************************
964 Personal firewall software may warn about the connection IDLE
965 makes to its subprocess using this computer's internal loopback
966 interface. This connection is not visible on any external
967 interface and no data is sent to or received from the Internet.
968 ****************************************************************
969 """
970
David Scherer7aced172000-08-15 01:13:23 +0000971 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +0000972 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +0000973 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000974 if use_subprocess:
975 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000976 client = self.interp.start_subprocess()
977 if not client:
978 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000979 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000980 else:
981 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000982 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000983 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000984 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000985 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +0000986 import tkinter
987 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000988 return True
David Scherer7aced172000-08-15 01:13:23 +0000989
990 def readline(self):
991 save = self.reading
992 try:
993 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000994 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +0000995 finally:
996 self.reading = save
997 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000998 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
999 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +00001000 self.resetoutput()
1001 if self.canceled:
1002 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001003 if not use_subprocess:
1004 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001005 if self.endoffile:
1006 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001007 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001008 return line
1009
1010 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001011 return True
David Scherer7aced172000-08-15 01:13:23 +00001012
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001013 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001014 try:
1015 if self.text.compare("sel.first", "!=", "sel.last"):
1016 return # Active selection -- always use default binding
1017 except:
1018 pass
1019 if not (self.executing or self.reading):
1020 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001021 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001022 self.showprompt()
1023 return "break"
1024 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001025 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001026 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001027 if self.interp.getdebugger():
1028 self.interp.restart_subprocess()
1029 else:
1030 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001031 if self.reading:
1032 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001033 return "break"
1034
1035 def eof_callback(self, event):
1036 if self.executing and not self.reading:
1037 return # Let the default binding (delete next char) take over
1038 if not (self.text.compare("iomark", "==", "insert") and
1039 self.text.compare("insert", "==", "end-1c")):
1040 return # Let the default binding (delete next char) take over
1041 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001042 self.resetoutput()
1043 self.close()
1044 else:
1045 self.canceled = 0
1046 self.endoffile = 1
1047 self.top.quit()
1048 return "break"
1049
David Scherer7aced172000-08-15 01:13:23 +00001050 def linefeed_callback(self, event):
1051 # Insert a linefeed without entering anything (still autoindented)
1052 if self.reading:
1053 self.text.insert("insert", "\n")
1054 self.text.see("insert")
1055 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001056 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001057 return "break"
1058
1059 def enter_callback(self, event):
1060 if self.executing and not self.reading:
1061 return # Let the default binding (insert '\n') take over
1062 # If some text is selected, recall the selection
1063 # (but only if this before the I/O mark)
1064 try:
1065 sel = self.text.get("sel.first", "sel.last")
1066 if sel:
1067 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001068 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001069 return "break"
1070 except:
1071 pass
1072 # If we're strictly before the line containing iomark, recall
1073 # the current line, less a leading prompt, less leading or
1074 # trailing whitespace
1075 if self.text.compare("insert", "<", "iomark linestart"):
1076 # Check if there's a relevant stdin range -- if so, use it
1077 prev = self.text.tag_prevrange("stdin", "insert")
1078 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001079 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001080 return "break"
1081 next = self.text.tag_nextrange("stdin", "insert")
1082 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001083 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001084 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001085 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001086 indices = self.text.tag_nextrange("console", "insert linestart")
1087 if indices and \
1088 self.text.compare(indices[0], "<=", "insert linestart"):
1089 self.recall(self.text.get(indices[1], "insert lineend"), event)
1090 else:
1091 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001092 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001093 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001094 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001095 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001096 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001097 # If we're in the current input and there's only whitespace
1098 # beyond the cursor, erase that whitespace first
1099 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001100 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001101 self.text.delete("insert", "end-1c")
1102 # If we're in the current input before its last line,
1103 # insert a newline right at the insert point
1104 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001105 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001106 return "break"
1107 # We're in the last line; append a newline and submit it
1108 self.text.mark_set("insert", "end-1c")
1109 if self.reading:
1110 self.text.insert("insert", "\n")
1111 self.text.see("insert")
1112 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001113 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001114 self.text.tag_add("stdin", "iomark", "end-1c")
1115 self.text.update_idletasks()
1116 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001117 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001118 else:
1119 self.runit()
1120 return "break"
1121
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001122 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001123 # remove leading and trailing empty or whitespace lines
1124 s = re.sub(r'^\s*\n', '' , s)
1125 s = re.sub(r'\n\s*$', '', s)
1126 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001127 self.text.undo_block_start()
1128 try:
1129 self.text.tag_remove("sel", "1.0", "end")
1130 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001131 prefix = self.text.get("insert linestart", "insert")
1132 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001133 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001134 prefix = self.text.get("insert linestart", "insert")
1135 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001136 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001137 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1138 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001139 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001140 if line.startswith(orig_base_indent):
1141 # replace orig base indentation with new indentation
1142 line = new_base_indent + line[len(orig_base_indent):]
1143 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001144 finally:
1145 self.text.see("insert")
1146 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001147
1148 def runit(self):
1149 line = self.text.get("iomark", "end-1c")
1150 # Strip off last newline and surrounding whitespace.
1151 # (To allow you to hit return twice to end a statement.)
1152 i = len(line)
1153 while i > 0 and line[i-1] in " \t":
1154 i = i-1
1155 if i > 0 and line[i-1] == "\n":
1156 i = i-1
1157 while i > 0 and line[i-1] in " \t":
1158 i = i-1
1159 line = line[:i]
1160 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001161
David Scherer7aced172000-08-15 01:13:23 +00001162 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001163 if self.interp.rpcclt:
1164 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001165 try:
1166 sys.last_traceback
1167 except:
1168 tkMessageBox.showerror("No stack trace",
1169 "There is no stack trace yet.\n"
1170 "(sys.last_traceback is not defined)",
1171 master=self.text)
1172 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001173 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001174 sv = StackBrowser(self.root, self.flist)
1175
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001176 def view_restart_mark(self, event=None):
1177 self.text.see("iomark")
1178 self.text.see("restart")
1179
1180 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001181 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001182
David Scherer7aced172000-08-15 01:13:23 +00001183 def showprompt(self):
1184 self.resetoutput()
1185 try:
1186 s = str(sys.ps1)
1187 except:
1188 s = ""
1189 self.console.write(s)
1190 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001191 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001192 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001193
1194 def resetoutput(self):
1195 source = self.text.get("iomark", "end-1c")
1196 if self.history:
1197 self.history.history_store(source)
1198 if self.text.get("end-2c") != "\n":
1199 self.text.insert("end-1c", "\n")
1200 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001201 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001202
1203 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001204 try:
1205 self.text.mark_gravity("iomark", "right")
1206 OutputWindow.write(self, s, tags, "iomark")
1207 self.text.mark_gravity("iomark", "left")
1208 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001209 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1210 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001211 if self.canceled:
1212 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001213 if not use_subprocess:
1214 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001215
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001216class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001217
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001218 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001219 self.shell = shell
1220 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001221 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001222
1223 def write(self, s):
1224 self.shell.write(s, self.tags)
1225
Kurt B. Kaiser66aaf742007-08-09 18:00:23 +00001226 def writelines(self, lines):
1227 for line in lines:
1228 self.write(line)
David Scherer7aced172000-08-15 01:13:23 +00001229
1230 def flush(self):
1231 pass
1232
1233 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001234 return True
David Scherer7aced172000-08-15 01:13:23 +00001235
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001236
David Scherer7aced172000-08-15 01:13:23 +00001237usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001238
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001239USAGE: idle [-deins] [-t title] [file]*
1240 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1241 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001242
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001243 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001244 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001245
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001246The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001247
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001248 -e open an edit window
1249 -i open a shell window
1250
1251The following options imply -i and will open a shell:
1252
1253 -c cmd run the command in a shell, or
1254 -r file run script from file
1255
1256 -d enable the debugger
1257 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1258 -t title set title of shell window
1259
1260A default edit window will be bypassed when -c, -r, or - are used.
1261
1262[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1263
1264Examples:
1265
1266idle
1267 Open an edit window or shell depending on IDLE's configuration.
1268
1269idle foo.py foobar.py
1270 Edit the files, also open a shell if configured to start with shell.
1271
1272idle -est "Baz" foo.py
1273 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1274 window with the title "Baz".
1275
Neal Norwitz752abd02008-05-13 04:55:24 +00001276idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001277 Open a shell window and run the command, passing "-c" in sys.argv[0]
1278 and "foo" in sys.argv[1].
1279
1280idle -d -s -r foo.py "Hello World"
1281 Open a shell window, run a startup script, enable the debugger, and
1282 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1283 sys.argv[1].
1284
Neal Norwitz752abd02008-05-13 04:55:24 +00001285echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001286 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1287 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001288"""
1289
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001290def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001291 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001292
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001293 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001294 enable_shell = False
1295 enable_edit = False
1296 debug = False
1297 cmd = None
1298 script = None
1299 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001300 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001301 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001302 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001303 sys.stderr.write("Error: %s\n" % str(msg))
1304 sys.stderr.write(usage_msg)
1305 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001306 for o, a in opts:
1307 if o == '-c':
1308 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001309 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001310 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001311 debug = True
1312 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001313 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001314 enable_edit = True
1315 if o == '-h':
1316 sys.stdout.write(usage_msg)
1317 sys.exit()
1318 if o == '-i':
1319 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001320 if o == '-n':
1321 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001322 if o == '-r':
1323 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001324 if os.path.isfile(script):
1325 pass
1326 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001327 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001328 sys.exit()
1329 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001330 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001331 startup = True
1332 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001333 if o == '-t':
1334 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001335 enable_shell = True
1336 if args and args[0] == '-':
1337 cmd = sys.stdin.read()
1338 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001339 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001340 for i in range(len(sys.path)):
1341 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001342 if args and args[0] == '-':
1343 sys.argv = [''] + args[1:]
1344 elif cmd:
1345 sys.argv = ['-c'] + args
1346 elif script:
1347 sys.argv = [script] + args
1348 elif args:
1349 enable_edit = True
1350 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001351 for filename in args:
1352 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001353 for dir in pathx:
1354 dir = os.path.abspath(dir)
1355 if not dir in sys.path:
1356 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001357 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001358 dir = os.getcwd()
1359 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001360 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001361 # check the IDLE settings configuration (but command line overrides)
1362 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001363 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001365 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001366 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001367 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001368
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001369 fixwordbreaks(root)
1370 root.withdraw()
1371 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001372 macosxSupport.setupApp(root, flist)
1373
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001374 if enable_edit:
1375 if not (cmd or script):
1376 for filename in args:
1377 flist.open(filename)
1378 if not args:
1379 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001380 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001381 shell = flist.open_shell()
1382 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001383 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001384
1385 if macosxSupport.runningAsOSXApp() and flist.dict:
1386 # On OSX: when the user has double-clicked on a file that causes
1387 # IDLE to be launched the shell window will open just in front of
1388 # the file she wants to see. Lower the interpreter window when
1389 # there are open files.
1390 shell.top.lower()
1391
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001392 shell = flist.pyshell
1393 # handle remaining options:
1394 if debug:
1395 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001396 if startup:
1397 filename = os.environ.get("IDLESTARTUP") or \
1398 os.environ.get("PYTHONSTARTUP")
1399 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001400 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001401 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001402 shell.interp.runcommand("""if 1:
1403 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001404 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001405 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001406 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001407 if cmd:
1408 shell.interp.execsource(cmd)
1409 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001410 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001411 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001412
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001413 root.mainloop()
1414 root.destroy()
1415
David Scherer7aced172000-08-15 01:13:23 +00001416if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001417 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001418 main()