blob: edc9334f9c4b80ce5e3f80f9c8d0424bc819334c [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. Kaisere866c812009-04-04 21:07:39 +000037HOST = '127.0.0.1' # python execution server on localhost loopback
38PORT = 0 # someday pass in host, port for remote debug capability
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000039
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000040try:
41 from signal import SIGTERM
42except ImportError:
43 SIGTERM = 15
44
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000045# Override warnings module to write to warning_stream. Initialize to send IDLE
46# internal warnings to the console. ScriptBinding.check_syntax() will
47# temporarily redirect the stream to the shell window to display warnings when
48# checking user's code.
49global warning_stream
50warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000051try:
52 import warnings
53except ImportError:
54 pass
55else:
Benjamin Peterson206e3072008-10-19 14:07:49 +000056 def idle_showwarning(message, category, filename, lineno,
57 file=None, line=None):
Guilherme Polo1fff0082009-08-14 15:05:30 +000058 if file is None:
59 file = warning_stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000060 try:
Guilherme Polo1fff0082009-08-14 15:05:30 +000061 file.write(warnings.formatwarning(message, category, filename,
Benjamin Peterson206e3072008-10-19 14:07:49 +000062 lineno, file=file, line=line))
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000063 except IOError:
64 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000065 warnings.showwarning = idle_showwarning
Guilherme Polo1fff0082009-08-14 15:05:30 +000066 def idle_formatwarning(message, category, filename, lineno, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000067 """Format warnings the IDLE way"""
68 s = "\nWarning (from warnings module):\n"
69 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polo1fff0082009-08-14 15:05:30 +000070 if line is None:
71 line = linecache.getline(filename, lineno)
72 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000073 if line:
74 s += " %s\n" % line
75 s += "%s: %s\n>>> " % (category.__name__, message)
76 return s
77 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000078
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000079def extended_linecache_checkcache(filename=None,
80 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000081 """Extend linecache.checkcache to preserve the <pyshell#...> entries
82
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000083 Rather than repeating the linecache code, patch it to save the
84 <pyshell#...> entries, call the original linecache.checkcache()
Guilherme Polo1fff0082009-08-14 15:05:30 +000085 (skipping them), and then restore the saved entries.
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000086
87 orig_checkcache is bound at definition time to the original
88 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000089 """
David Scherer7aced172000-08-15 01:13:23 +000090 cache = linecache.cache
91 save = {}
Guilherme Polo1fff0082009-08-14 15:05:30 +000092 for key in list(cache):
93 if key[:1] + key[-1:] == '<>':
94 save[key] = cache.pop(key)
95 orig_checkcache(filename)
David Scherer7aced172000-08-15 01:13:23 +000096 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000097
Kurt B. Kaiser81885592002-11-29 22:10:53 +000098# Patch linecache.checkcache():
99linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +0000100
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000101
David Scherer7aced172000-08-15 01:13:23 +0000102class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000103 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000104
David Scherer7aced172000-08-15 01:13:23 +0000105 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000106 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000107 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000108 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000109 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000110 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
111
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000112 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
113 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000114 # whenever a file is changed, restore breakpoints
115 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000116 def filename_changed_hook(old_hook=self.io.filename_change_hook,
117 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000118 self.restore_file_breaks()
119 old_hook()
120 self.io.set_filename_change_hook(filename_changed_hook)
121
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000122 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
123 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000124
Chui Teya2adb0f2002-11-04 22:14:54 +0000125 def set_breakpoint(self, lineno):
126 text = self.text
127 filename = self.io.filename
128 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
129 try:
130 i = self.breakpoints.index(lineno)
131 except ValueError: # only add if missing, i.e. do once
132 self.breakpoints.append(lineno)
133 try: # update the subprocess debugger
134 debug = self.flist.pyshell.interp.debugger
135 debug.set_breakpoint_here(filename, lineno)
136 except: # but debugger may not be active right now....
137 pass
138
David Scherer7aced172000-08-15 01:13:23 +0000139 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000140 text = self.text
141 filename = self.io.filename
142 if not filename:
143 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000144 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000145 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000146 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000147
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000148 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000149 text = self.text
150 filename = self.io.filename
151 if not filename:
152 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000153 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000154 lineno = int(float(text.index("insert")))
155 try:
156 self.breakpoints.remove(lineno)
157 except:
158 pass
159 text.tag_remove("BREAK", "insert linestart",\
160 "insert lineend +1char")
161 try:
162 debug = self.flist.pyshell.interp.debugger
163 debug.clear_breakpoint_here(filename, lineno)
164 except:
165 pass
166
167 def clear_file_breaks(self):
168 if self.breakpoints:
169 text = self.text
170 filename = self.io.filename
171 if not filename:
172 text.bell()
173 return
174 self.breakpoints = []
175 text.tag_remove("BREAK", "1.0", END)
176 try:
177 debug = self.flist.pyshell.interp.debugger
178 debug.clear_file_breaks(filename)
179 except:
180 pass
181
Chui Teya2adb0f2002-11-04 22:14:54 +0000182 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000183 "Save breakpoints when file is saved"
184 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
185 # be run. The breaks are saved at that time. If we introduce
186 # a temporary file save feature the save breaks functionality
187 # needs to be re-verified, since the breaks at the time the
188 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000189 # permanent save of the file. Currently, a break introduced
190 # after a save will be effective, but not persistent.
191 # This is necessary to keep the saved breaks synched with the
192 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000193 #
194 # Breakpoints are set as tagged ranges in the text. Certain
195 # kinds of edits cause these ranges to be deleted: Inserting
196 # or deleting a line just before a breakpoint, and certain
197 # deletions prior to a breakpoint. These issues need to be
198 # investigated and understood. It's not clear if they are
199 # Tk issues or IDLE issues, or whether they can actually
200 # be fixed. Since a modified file has to be saved before it is
201 # run, and since self.breakpoints (from which the subprocess
202 # debugger is loaded) is updated during the save, the visible
203 # breaks stay synched with the subprocess even if one of these
204 # unexpected breakpoint deletions occurs.
205 breaks = self.breakpoints
206 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000207 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000208 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 lines = []
211 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000212 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000213 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000214 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000215 self.update_breakpoints()
216 breaks = self.breakpoints
217 if breaks:
218 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000219 new_file.close()
220
221 def restore_file_breaks(self):
222 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000223 filename = self.io.filename
224 if filename is None:
225 return
Chui Tey69371d62002-11-04 23:39:45 +0000226 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000227 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000228 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000229 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000230 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000231 for breakpoint_linenumber in breakpoint_linenumbers:
232 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000233
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000234 def update_breakpoints(self):
235 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000236 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000237 ranges = text.tag_ranges("BREAK")
238 linenumber_list = self.ranges_to_linenumbers(ranges)
239 self.breakpoints = linenumber_list
240
241 def ranges_to_linenumbers(self, ranges):
242 lines = []
243 for index in range(0, len(ranges), 2):
244 lineno = int(float(ranges[index]))
245 end = int(float(ranges[index+1]))
246 while lineno < end:
247 lines.append(lineno)
248 lineno += 1
249 return lines
250
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000251# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000252# def saved_change_hook(self):
253# "Extend base method - clear breaks if module is modified"
254# if not self.get_saved():
255# self.clear_file_breaks()
256# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000257
258 def _close(self):
259 "Extend base method - clear breaks when module is closed"
260 self.clear_file_breaks()
261 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000262
David Scherer7aced172000-08-15 01:13:23 +0000263
264class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000265 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000266
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000267 # override FileList's class variable, instances return PyShellEditorWindow
268 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000269 EditorWindow = PyShellEditorWindow
270
271 pyshell = None
272
273 def open_shell(self, event=None):
274 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000275 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000276 else:
277 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000278 if self.pyshell:
279 if not self.pyshell.begin():
280 return None
David Scherer7aced172000-08-15 01:13:23 +0000281 return self.pyshell
282
283
284class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000285 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000286
Steven M. Gavab77d3432002-03-02 07:16:21 +0000287 def __init__(self):
288 ColorDelegator.__init__(self)
289 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000290
291 def recolorize_main(self):
292 self.tag_remove("TODO", "1.0", "iomark")
293 self.tag_add("SYNC", "1.0", "iomark")
294 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000295
Steven M. Gavab77d3432002-03-02 07:16:21 +0000296 def LoadTagDefs(self):
297 ColorDelegator.LoadTagDefs(self)
298 theme = idleConf.GetOption('main','Theme','name')
299 self.tagdefs.update({
300 "stdin": {'background':None,'foreground':None},
301 "stdout": idleConf.GetHighlight(theme, "stdout"),
302 "stderr": idleConf.GetHighlight(theme, "stderr"),
303 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000304 })
David Scherer7aced172000-08-15 01:13:23 +0000305
David Scherer7aced172000-08-15 01:13:23 +0000306class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000307 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000308
309 def insert(self, index, chars, tags=None):
310 try:
311 if self.delegate.compare(index, "<", "iomark"):
312 self.delegate.bell()
313 return
314 except TclError:
315 pass
316 UndoDelegator.insert(self, index, chars, tags)
317
318 def delete(self, index1, index2=None):
319 try:
320 if self.delegate.compare(index1, "<", "iomark"):
321 self.delegate.bell()
322 return
323 except TclError:
324 pass
325 UndoDelegator.delete(self, index1, index2)
326
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000327
328class MyRPCClient(rpc.RPCClient):
329
330 def handle_EOF(self):
331 "Override the base class - just re-raise EOFError"
332 raise EOFError
333
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000334
David Scherer7aced172000-08-15 01:13:23 +0000335class ModifiedInterpreter(InteractiveInterpreter):
336
337 def __init__(self, tkconsole):
338 self.tkconsole = tkconsole
339 locals = sys.modules['__main__'].__dict__
340 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000341 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000342 self.restarting = False
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000343 self.subprocess_arglist = None
344 self.port = PORT
David Scherer7aced172000-08-15 01:13:23 +0000345
Chui Tey5d2af632002-05-26 13:36:41 +0000346 rpcclt = None
347 rpcpid = None
348
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000349 def spawn_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000350 if self.subprocess_arglist == None:
351 self.subprocess_arglist = self.build_subprocess_arglist()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000352 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000353 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000354
Tony Lowndsf53dec22002-12-20 04:24:43 +0000355 def build_subprocess_arglist(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000356 assert (self.port!=0), (
357 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000358 w = ['-W' + s for s in sys.warnoptions]
359 # Maybe IDLE is installed and is being accessed via sys.path,
360 # or maybe it's not installed and the idle.py script is being
361 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000362 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
363 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000364 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000365 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000366 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000367 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000368 if sys.platform[:3] == 'win' and ' ' in sys.executable:
369 # handle embedded space in path by quoting the argument
370 decorated_exec = '"%s"' % sys.executable
371 else:
372 decorated_exec = sys.executable
373 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000374
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000375 def start_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000376 addr = (HOST, self.port)
377 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000378 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000379 time.sleep(i)
380 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000381 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000382 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000383 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000384 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000385 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000386 self.display_port_binding_error()
387 return None
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000388 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
389 self.port = self.rpcclt.listening_sock.getsockname()[1]
390 # if PORT was not 0, probably working with a remote execution server
391 if PORT != 0:
392 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
393 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
394 # on Windows since the implementation allows two active sockets on
395 # the same address!
396 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
397 socket.SO_REUSEADDR, 1)
398 self.spawn_subprocess()
399 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000400 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000401 self.rpcclt.listening_sock.settimeout(10)
402 try:
403 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000404 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000405 self.display_no_subprocess_error()
406 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000407 self.rpcclt.register("stdin", self.tkconsole)
408 self.rpcclt.register("stdout", self.tkconsole.stdout)
409 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000410 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000411 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000412 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000413 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000414 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000415 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000416
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000417 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000418 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000419 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000420 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000421 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000422 debug = self.getdebugger()
423 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000424 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000425 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000426 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
427 except:
428 pass
429 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000430 self.rpcclt.close()
431 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000432 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000433 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000434 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000435 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000436 try:
437 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000438 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000439 self.display_no_subprocess_error()
440 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000441 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000442 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000443 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000444 if was_executing:
445 console.write('\n')
446 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000447 halfbar = ((int(console.width) - 16) // 2) * '='
448 console.write(halfbar + ' RESTART ' + halfbar)
449 console.text.mark_set("restart", "end-1c")
450 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000451 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000453 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000454 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000455 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000456 # reload remote debugger breakpoints for all PyShellEditWindows
457 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000458 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000459 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000460
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000461 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000462 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000463
464 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000465 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000466
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000467 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000468 try:
469 self.rpcclt.close()
470 except AttributeError: # no socket
471 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000472 self.unix_terminate()
473 self.tkconsole.executing = False
474 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000475
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000476 def unix_terminate(self):
477 "UNIX: make sure subprocess is terminated and collect status"
478 if hasattr(os, 'kill'):
479 try:
480 os.kill(self.rpcpid, SIGTERM)
481 except OSError:
482 # process already terminated:
483 return
484 else:
485 try:
486 os.waitpid(self.rpcpid, 0)
487 except OSError:
488 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000489
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000490 def transfer_path(self):
491 self.runcommand("""if 1:
492 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000493 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000494 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000495 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000496
Chui Tey5d2af632002-05-26 13:36:41 +0000497 active_seq = None
498
499 def poll_subprocess(self):
500 clt = self.rpcclt
501 if clt is None:
502 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000503 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000504 response = clt.pollresponse(self.active_seq, wait=0.05)
505 except (EOFError, IOError, KeyboardInterrupt):
506 # lost connection or subprocess terminated itself, restart
507 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000508 if self.tkconsole.closing:
509 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000510 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000511 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000512 if response:
513 self.tkconsole.resetoutput()
514 self.active_seq = None
515 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000516 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000517 if how == "OK":
518 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000519 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000520 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000521 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
522 self.remote_stack_viewer()
523 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000524 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000525 print(errmsg, what, file=sys.__stderr__)
526 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000527 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000528 try:
529 self.tkconsole.endexecuting()
530 except AttributeError: # shell may have closed
531 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000532 # Reschedule myself
533 if not self.tkconsole.closing:
534 self.tkconsole.text.after(self.tkconsole.pollinterval,
535 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000536
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000537 debugger = None
538
539 def setdebugger(self, debugger):
540 self.debugger = debugger
541
542 def getdebugger(self):
543 return self.debugger
544
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000545 def open_remote_stack_viewer(self):
546 """Initiate the remote stack viewer from a separate thread.
547
548 This method is called from the subprocess, and by returning from this
549 method we allow the subprocess to unblock. After a bit the shell
550 requests the subprocess to open the remote stack viewer which returns a
551 static object looking at the last exceptiopn. It is queried through
552 the RPC mechanism.
553
554 """
555 self.tkconsole.text.after(300, self.remote_stack_viewer)
556 return
557
Chui Tey5d2af632002-05-26 13:36:41 +0000558 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000559 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000560 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000561 if oid is None:
562 self.tkconsole.root.bell()
563 return
564 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000565 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000566 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000567 theme = idleConf.GetOption('main','Theme','name')
568 background = idleConf.GetHighlight(theme, 'normal')['background']
569 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000570 sc.frame.pack(expand=1, fill="both")
571 node = TreeNode(sc.canvas, None, item)
572 node.expand()
573 # XXX Should GC the remote tree when closing the window
574
David Scherer7aced172000-08-15 01:13:23 +0000575 gid = 0
576
577 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000578 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000579 filename = self.stuffsource(source)
580 self.execfile(filename, source)
581
582 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000583 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000584 if source is None:
585 source = open(filename, "r").read()
586 try:
587 code = compile(source, filename, "exec")
588 except (OverflowError, SyntaxError):
589 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000590 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000591 print('*** Error in script or command!\n', file=tkerr)
592 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000593 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000594 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000595 else:
596 self.runcode(code)
597
598 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000599 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000600 filename = self.stuffsource(source)
601 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000602 self.save_warnings_filters = warnings.filters[:]
603 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000604 # at the moment, InteractiveInterpreter expects str
605 assert isinstance(source, str)
606 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000607 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000608 # try:
609 # source = source.encode(IOBinding.encoding)
610 # except UnicodeError:
611 # self.tkconsole.resetoutput()
612 # self.write("Unsupported characters in input\n")
613 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000614 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000615 # InteractiveInterpreter.runsource() calls its runcode() method,
616 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000617 return InteractiveInterpreter.runsource(self, source, filename)
618 finally:
619 if self.save_warnings_filters is not None:
620 warnings.filters[:] = self.save_warnings_filters
621 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000622
623 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000624 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000625 filename = "<pyshell#%d>" % self.gid
626 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000627 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000628 linecache.cache[filename] = len(source)+1, 0, lines, filename
629 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000630
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000631 def prepend_syspath(self, filename):
632 "Prepend sys.path with file's directory if not already included"
633 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000634 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000635 import sys as _sys
636 from os.path import dirname as _dirname
637 _dir = _dirname(_filename)
638 if not _dir in _sys.path:
639 _sys.path.insert(0, _dir)
640 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000641 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000642
David Scherer7aced172000-08-15 01:13:23 +0000643 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000644 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000645
646 Color the offending position instead of printing it and pointing at it
647 with a caret.
648
649 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000650 tkconsole = self.tkconsole
651 text = tkconsole.text
652 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000653 type, value, tb = sys.exc_info()
Guido van Rossum33d26892007-08-05 15:29:28 +0000654 msg = value.msg or "<no detail available>"
655 lineno = value.lineno or 1
656 offset = value.offset or 0
657 if offset == 0:
658 lineno += 1 #mark end of offending line
659 if lineno == 1:
660 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000661 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000662 pos = "iomark linestart + %d lines + %d chars" % \
663 (lineno-1, offset-1)
664 tkconsole.colorize_syntax_error(text, pos)
665 tkconsole.resetoutput()
666 self.write("SyntaxError: %s\n" % msg)
667 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000668
669 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000670 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000671 self.tkconsole.resetoutput()
672 self.checklinecache()
673 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000674 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
675 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000676
677 def checklinecache(self):
678 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000679 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000680 if key[:1] + key[-1:] != "<>":
681 del c[key]
682
Chui Tey5d2af632002-05-26 13:36:41 +0000683 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000684 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000685 # The code better not raise an exception!
686 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000687 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000688 return 0
689 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000690 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000691 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000692 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000693 return 1
694
David Scherer7aced172000-08-15 01:13:23 +0000695 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000696 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000697 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000698 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000699 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000700 if self.save_warnings_filters is not None:
701 warnings.filters[:] = self.save_warnings_filters
702 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000703 debugger = self.debugger
704 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000705 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000706 if not debugger and self.rpcclt is not None:
707 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
708 (code,), {})
709 elif debugger:
710 debugger.run(code, self.locals)
711 else:
712 exec(code, self.locals)
713 except SystemExit:
714 if not self.tkconsole.closing:
715 if tkMessageBox.askyesno(
716 "Exit?",
717 "Do you want to exit altogether?",
718 default="yes",
719 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000720 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000721 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000722 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000723 else:
724 raise
725 except:
726 if use_subprocess:
727 print("IDLE internal error in runcode()",
728 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000729 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000730 self.tkconsole.endexecuting()
731 else:
732 if self.tkconsole.canceled:
733 self.tkconsole.canceled = False
734 print("KeyboardInterrupt", file=self.tkconsole.stderr)
735 else:
736 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000737 finally:
738 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000739 try:
740 self.tkconsole.endexecuting()
741 except AttributeError: # shell may have closed
742 pass
David Scherer7aced172000-08-15 01:13:23 +0000743
744 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000745 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000746 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000747
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000748 def display_port_binding_error(self):
749 tkMessageBox.showerror(
750 "Port Binding Error",
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000751 "IDLE can't bind to a TCP/IP port, which is necessary to "
752 "communicate with its Python execution server. This might be "
753 "because no networking is installed on this computer. "
754 "Run IDLE with the -n command line switch to start without a "
755 "subprocess and refer to Help/IDLE Help 'Running without a "
756 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000757 master=self.tkconsole.text)
758
759 def display_no_subprocess_error(self):
760 tkMessageBox.showerror(
761 "Subprocess Startup Error",
762 "IDLE's subprocess didn't make connection. Either IDLE can't "
763 "start a subprocess or personal firewall software is blocking "
764 "the connection.",
765 master=self.tkconsole.text)
766
767 def display_executing_dialog(self):
768 tkMessageBox.showerror(
769 "Already executing",
770 "The Python Shell window is already executing a command; "
771 "please wait until it is finished.",
772 master=self.tkconsole.text)
773
774
David Scherer7aced172000-08-15 01:13:23 +0000775class PyShell(OutputWindow):
776
777 shell_title = "Python Shell"
778
779 # Override classes
780 ColorDelegator = ModifiedColorDelegator
781 UndoDelegator = ModifiedUndoDelegator
782
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000783 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000784 menu_specs = [
785 ("file", "_File"),
786 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000787 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000788 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000789 ("windows", "_Windows"),
790 ("help", "_Help"),
791 ]
David Scherer7aced172000-08-15 01:13:23 +0000792
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000793 if macosxSupport.runningAsOSXApp():
794 del menu_specs[-3]
795 menu_specs[-2] = ("windows", "_Window")
796
797
David Scherer7aced172000-08-15 01:13:23 +0000798 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000799 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000800
801 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000802 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000803 ms = self.menu_specs
804 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000805 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000806 self.interp = ModifiedInterpreter(self)
807 if flist is None:
808 root = Tk()
809 fixwordbreaks(root)
810 root.withdraw()
811 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000812 #
David Scherer7aced172000-08-15 01:13:23 +0000813 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000814 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000815## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
816 self.usetabs = True
817 # indentwidth must be 8 when using tabs. See note in EditorWindow:
818 self.indentwidth = 8
819 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000820 #
David Scherer7aced172000-08-15 01:13:23 +0000821 text = self.text
822 text.configure(wrap="char")
823 text.bind("<<newline-and-indent>>", self.enter_callback)
824 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
825 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000826 text.bind("<<end-of-file>>", self.eof_callback)
827 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000828 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000829 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8a78cad2007-12-13 03:38:16 +0000830 self.color = color = self.ColorDelegator()
831 self.per.insertfilter(color)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000832 if use_subprocess:
833 text.bind("<<view-restart>>", self.view_restart_mark)
834 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000835 #
David Scherer7aced172000-08-15 01:13:23 +0000836 self.save_stdout = sys.stdout
837 self.save_stderr = sys.stderr
838 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000839 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000840 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
841 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
842 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000843 if not use_subprocess:
844 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000845 sys.stderr = self.stderr
Chui Tey5d2af632002-05-26 13:36:41 +0000846 sys.stdin = self
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000847 try:
848 # page help() text to shell.
849 import pydoc # import must be done here to capture i/o rebinding.
850 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
851 pydoc.pager = pydoc.plainpager
852 except:
853 sys.stderr = sys.__stderr__
854 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000855 #
David Scherer7aced172000-08-15 01:13:23 +0000856 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000857 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000858 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000859
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000860 def get_standard_extension_names(self):
861 return idleConf.GetExtensions(shell_only=True)
862
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000863 reading = False
864 executing = False
865 canceled = False
866 endoffile = False
867 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000868
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000869 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000870 global warning_stream
871 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000872
873 def get_warning_stream(self):
874 return warning_stream
875
David Scherer7aced172000-08-15 01:13:23 +0000876 def toggle_debugger(self, event=None):
877 if self.executing:
878 tkMessageBox.showerror("Don't debug now",
879 "You can only toggle the debugger when idle",
880 master=self.text)
881 self.set_debugger_indicator()
882 return "break"
883 else:
884 db = self.interp.getdebugger()
885 if db:
886 self.close_debugger()
887 else:
888 self.open_debugger()
889
890 def set_debugger_indicator(self):
891 db = self.interp.getdebugger()
892 self.setvar("<<toggle-debugger>>", not not db)
893
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000894 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000895 pass # All we need is the variable
896
897 def close_debugger(self):
898 db = self.interp.getdebugger()
899 if db:
900 self.interp.setdebugger(None)
901 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000902 if self.interp.rpcclt:
903 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000904 self.resetoutput()
905 self.console.write("[DEBUG OFF]\n")
906 sys.ps1 = ">>> "
907 self.showprompt()
908 self.set_debugger_indicator()
909
910 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000911 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000912 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
913 self)
914 else:
915 dbg_gui = Debugger.Debugger(self)
916 self.interp.setdebugger(dbg_gui)
917 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000918 sys.ps1 = "[DEBUG ON]\n>>> "
919 self.showprompt()
920 self.set_debugger_indicator()
921
David Scherer7aced172000-08-15 01:13:23 +0000922 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000923 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000924 self.resetoutput()
925 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000926
927 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000928 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000929 self.executing = 0
930 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000931 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000932
933 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000934 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000935 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000936 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000937 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000938 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000939 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000940 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000941 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000942 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000943 if self.reading:
944 self.top.quit()
945 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000946 self.closing = True
947 # Wait for poll_subprocess() rescheduling to stop
948 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000949
950 def close2(self):
951 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000952
953 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000954 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000955 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000956 if use_subprocess:
957 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000958 # Restore std streams
959 sys.stdout = self.save_stdout
960 sys.stderr = self.save_stderr
961 sys.stdin = self.save_stdin
962 # Break cycles
963 self.interp = None
964 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000965 self.flist.pyshell = None
966 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000967 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000968
969 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000970 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000971 return True
David Scherer7aced172000-08-15 01:13:23 +0000972
973 def short_title(self):
974 return self.shell_title
975
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000976 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000977 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000978
David Scherer7aced172000-08-15 01:13:23 +0000979 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +0000980 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +0000981 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000982 if use_subprocess:
983 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000984 client = self.interp.start_subprocess()
985 if not client:
986 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000987 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000988 else:
989 nosub = "==== No Subprocess ===="
Raymond Hettingera2a8e8b2009-01-27 00:28:36 +0000990 self.write("Python %s on %s\n%s\n%s" %
991 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000992 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +0000993 import tkinter
994 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000995 return True
David Scherer7aced172000-08-15 01:13:23 +0000996
997 def readline(self):
998 save = self.reading
999 try:
1000 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001001 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001002 finally:
1003 self.reading = save
1004 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001005 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1006 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +00001007 self.resetoutput()
1008 if self.canceled:
1009 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001010 if not use_subprocess:
1011 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001012 if self.endoffile:
1013 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001014 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001015 return line
1016
1017 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001018 return True
David Scherer7aced172000-08-15 01:13:23 +00001019
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001020 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001021 try:
1022 if self.text.compare("sel.first", "!=", "sel.last"):
1023 return # Active selection -- always use default binding
1024 except:
1025 pass
1026 if not (self.executing or self.reading):
1027 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001028 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001029 self.showprompt()
1030 return "break"
1031 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001032 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001033 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001034 if self.interp.getdebugger():
1035 self.interp.restart_subprocess()
1036 else:
1037 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001038 if self.reading:
1039 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001040 return "break"
1041
1042 def eof_callback(self, event):
1043 if self.executing and not self.reading:
1044 return # Let the default binding (delete next char) take over
1045 if not (self.text.compare("iomark", "==", "insert") and
1046 self.text.compare("insert", "==", "end-1c")):
1047 return # Let the default binding (delete next char) take over
1048 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001049 self.resetoutput()
1050 self.close()
1051 else:
1052 self.canceled = 0
1053 self.endoffile = 1
1054 self.top.quit()
1055 return "break"
1056
David Scherer7aced172000-08-15 01:13:23 +00001057 def linefeed_callback(self, event):
1058 # Insert a linefeed without entering anything (still autoindented)
1059 if self.reading:
1060 self.text.insert("insert", "\n")
1061 self.text.see("insert")
1062 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001063 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001064 return "break"
1065
1066 def enter_callback(self, event):
1067 if self.executing and not self.reading:
1068 return # Let the default binding (insert '\n') take over
1069 # If some text is selected, recall the selection
1070 # (but only if this before the I/O mark)
1071 try:
1072 sel = self.text.get("sel.first", "sel.last")
1073 if sel:
1074 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001075 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001076 return "break"
1077 except:
1078 pass
1079 # If we're strictly before the line containing iomark, recall
1080 # the current line, less a leading prompt, less leading or
1081 # trailing whitespace
1082 if self.text.compare("insert", "<", "iomark linestart"):
1083 # Check if there's a relevant stdin range -- if so, use it
1084 prev = self.text.tag_prevrange("stdin", "insert")
1085 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001086 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001087 return "break"
1088 next = self.text.tag_nextrange("stdin", "insert")
1089 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001090 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001091 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001092 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001093 indices = self.text.tag_nextrange("console", "insert linestart")
1094 if indices and \
1095 self.text.compare(indices[0], "<=", "insert linestart"):
1096 self.recall(self.text.get(indices[1], "insert lineend"), event)
1097 else:
1098 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001099 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001100 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001101 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001102 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001103 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001104 # If we're in the current input and there's only whitespace
1105 # beyond the cursor, erase that whitespace first
1106 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001107 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001108 self.text.delete("insert", "end-1c")
1109 # If we're in the current input before its last line,
1110 # insert a newline right at the insert point
1111 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001112 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001113 return "break"
1114 # We're in the last line; append a newline and submit it
1115 self.text.mark_set("insert", "end-1c")
1116 if self.reading:
1117 self.text.insert("insert", "\n")
1118 self.text.see("insert")
1119 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001120 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001121 self.text.tag_add("stdin", "iomark", "end-1c")
1122 self.text.update_idletasks()
1123 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001124 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001125 else:
1126 self.runit()
1127 return "break"
1128
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001129 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001130 # remove leading and trailing empty or whitespace lines
1131 s = re.sub(r'^\s*\n', '' , s)
1132 s = re.sub(r'\n\s*$', '', s)
1133 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001134 self.text.undo_block_start()
1135 try:
1136 self.text.tag_remove("sel", "1.0", "end")
1137 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001138 prefix = self.text.get("insert linestart", "insert")
1139 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001140 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001141 prefix = self.text.get("insert linestart", "insert")
1142 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001143 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001144 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1145 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001146 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001147 if line.startswith(orig_base_indent):
1148 # replace orig base indentation with new indentation
1149 line = new_base_indent + line[len(orig_base_indent):]
1150 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001151 finally:
1152 self.text.see("insert")
1153 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001154
1155 def runit(self):
1156 line = self.text.get("iomark", "end-1c")
1157 # Strip off last newline and surrounding whitespace.
1158 # (To allow you to hit return twice to end a statement.)
1159 i = len(line)
1160 while i > 0 and line[i-1] in " \t":
1161 i = i-1
1162 if i > 0 and line[i-1] == "\n":
1163 i = i-1
1164 while i > 0 and line[i-1] in " \t":
1165 i = i-1
1166 line = line[:i]
1167 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001168
David Scherer7aced172000-08-15 01:13:23 +00001169 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001170 if self.interp.rpcclt:
1171 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001172 try:
1173 sys.last_traceback
1174 except:
1175 tkMessageBox.showerror("No stack trace",
1176 "There is no stack trace yet.\n"
1177 "(sys.last_traceback is not defined)",
1178 master=self.text)
1179 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001180 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001181 sv = StackBrowser(self.root, self.flist)
1182
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001183 def view_restart_mark(self, event=None):
1184 self.text.see("iomark")
1185 self.text.see("restart")
1186
1187 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001188 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001189
David Scherer7aced172000-08-15 01:13:23 +00001190 def showprompt(self):
1191 self.resetoutput()
1192 try:
1193 s = str(sys.ps1)
1194 except:
1195 s = ""
1196 self.console.write(s)
1197 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001198 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001199 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001200
1201 def resetoutput(self):
1202 source = self.text.get("iomark", "end-1c")
1203 if self.history:
1204 self.history.history_store(source)
1205 if self.text.get("end-2c") != "\n":
1206 self.text.insert("end-1c", "\n")
1207 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001208 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001209
1210 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001211 try:
1212 self.text.mark_gravity("iomark", "right")
1213 OutputWindow.write(self, s, tags, "iomark")
1214 self.text.mark_gravity("iomark", "left")
1215 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001216 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1217 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001218 if self.canceled:
1219 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001220 if not use_subprocess:
1221 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001222
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001223class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001224
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001225 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001226 self.shell = shell
1227 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001228 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001229
1230 def write(self, s):
1231 self.shell.write(s, self.tags)
1232
Kurt B. Kaiser66aaf742007-08-09 18:00:23 +00001233 def writelines(self, lines):
1234 for line in lines:
1235 self.write(line)
David Scherer7aced172000-08-15 01:13:23 +00001236
1237 def flush(self):
1238 pass
1239
1240 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001241 return True
David Scherer7aced172000-08-15 01:13:23 +00001242
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001243
David Scherer7aced172000-08-15 01:13:23 +00001244usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001245
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001246USAGE: idle [-deins] [-t title] [file]*
1247 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1248 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001249
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001250 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001251 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001252
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001253The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001254
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001255 -e open an edit window
1256 -i open a shell window
1257
1258The following options imply -i and will open a shell:
1259
1260 -c cmd run the command in a shell, or
1261 -r file run script from file
1262
1263 -d enable the debugger
1264 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1265 -t title set title of shell window
1266
1267A default edit window will be bypassed when -c, -r, or - are used.
1268
1269[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1270
1271Examples:
1272
1273idle
1274 Open an edit window or shell depending on IDLE's configuration.
1275
1276idle foo.py foobar.py
1277 Edit the files, also open a shell if configured to start with shell.
1278
1279idle -est "Baz" foo.py
1280 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1281 window with the title "Baz".
1282
Neal Norwitz752abd02008-05-13 04:55:24 +00001283idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001284 Open a shell window and run the command, passing "-c" in sys.argv[0]
1285 and "foo" in sys.argv[1].
1286
1287idle -d -s -r foo.py "Hello World"
1288 Open a shell window, run a startup script, enable the debugger, and
1289 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1290 sys.argv[1].
1291
Neal Norwitz752abd02008-05-13 04:55:24 +00001292echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001293 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1294 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001295"""
1296
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001297def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001298 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001299
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001300 use_subprocess = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001301 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001302 enable_edit = False
1303 debug = False
1304 cmd = None
1305 script = None
1306 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001307 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001308 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001309 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001310 sys.stderr.write("Error: %s\n" % str(msg))
1311 sys.stderr.write(usage_msg)
1312 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001313 for o, a in opts:
1314 if o == '-c':
1315 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001316 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001317 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001318 debug = True
1319 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001320 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001321 enable_edit = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001322 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001323 if o == '-h':
1324 sys.stdout.write(usage_msg)
1325 sys.exit()
1326 if o == '-i':
1327 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001328 if o == '-n':
1329 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001330 if o == '-r':
1331 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001332 if os.path.isfile(script):
1333 pass
1334 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001335 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001336 sys.exit()
1337 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001338 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001339 startup = True
1340 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001341 if o == '-t':
1342 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001343 enable_shell = True
1344 if args and args[0] == '-':
1345 cmd = sys.stdin.read()
1346 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001347 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001348 for i in range(len(sys.path)):
1349 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001350 if args and args[0] == '-':
1351 sys.argv = [''] + args[1:]
1352 elif cmd:
1353 sys.argv = ['-c'] + args
1354 elif script:
1355 sys.argv = [script] + args
1356 elif args:
1357 enable_edit = True
1358 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001359 for filename in args:
1360 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001361 for dir in pathx:
1362 dir = os.path.abspath(dir)
1363 if not dir in sys.path:
1364 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001365 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001366 dir = os.getcwd()
1367 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001368 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001369 # check the IDLE settings configuration (but command line overrides)
1370 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001371 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001372 enable_edit = enable_edit or edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001373 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001374 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001375
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001376 fixwordbreaks(root)
1377 root.withdraw()
1378 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001379 macosxSupport.setupApp(root, flist)
1380
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001381 if enable_edit:
1382 if not (cmd or script):
1383 for filename in args:
1384 flist.open(filename)
1385 if not args:
1386 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001387 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001388 shell = flist.open_shell()
1389 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001390 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001391
1392 if macosxSupport.runningAsOSXApp() and flist.dict:
1393 # On OSX: when the user has double-clicked on a file that causes
1394 # IDLE to be launched the shell window will open just in front of
1395 # the file she wants to see. Lower the interpreter window when
1396 # there are open files.
1397 shell.top.lower()
1398
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001399 shell = flist.pyshell
1400 # handle remaining options:
1401 if debug:
1402 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001403 if startup:
1404 filename = os.environ.get("IDLESTARTUP") or \
1405 os.environ.get("PYTHONSTARTUP")
1406 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001407 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001408 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001409 shell.interp.runcommand("""if 1:
1410 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001411 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001412 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001413 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001414 if cmd:
1415 shell.interp.execsource(cmd)
1416 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001417 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001418 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001419
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001420 root.mainloop()
1421 root.destroy()
1422
David Scherer7aced172000-08-15 01:13:23 +00001423if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001424 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001425 main()