blob: 865472eb19e4a70e83e72625cd921695554ff609 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
David Scherer7aced172000-08-15 01:13:23 +00002
Victor Stinner979482a2011-09-02 01:00:40 +02003import getopt
David Scherer7aced172000-08-15 01:13:23 +00004import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00005import os.path
David Scherer7aced172000-08-15 01:13:23 +00006import re
Chui Tey5d2af632002-05-26 13:36:41 +00007import socket
Victor Stinner979482a2011-09-02 01:00:40 +02008import subprocess
9import sys
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000010import threading
Victor Stinner979482a2011-09-02 01:00:40 +020011import time
12import tokenize
Chui Tey5d2af632002-05-26 13:36:41 +000013import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000014import types
Martin v. Löwisc882b7c2012-07-25 10:47:20 +020015import io
David Scherer7aced172000-08-15 01:13:23 +000016
17import linecache
18from code import InteractiveInterpreter
19
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000020try:
Georg Brandl14fc4272008-05-17 18:39:55 +000021 from tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000022except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000023 print("** IDLE can't import Tkinter. " \
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000024 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000025 sys.exit(1)
Georg Brandl14fc4272008-05-17 18:39:55 +000026import tkinter.messagebox as tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000027
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000028from idlelib.EditorWindow import EditorWindow, fixwordbreaks
29from idlelib.FileList import FileList
30from idlelib.ColorDelegator import ColorDelegator
31from idlelib.UndoDelegator import UndoDelegator
32from idlelib.OutputWindow import OutputWindow
33from idlelib.configHandler import idleConf
34from idlelib import idlever
35from idlelib import rpc
36from idlelib import Debugger
37from idlelib import RemoteDebugger
38from idlelib import macosxSupport
Chui Tey5d2af632002-05-26 13:36:41 +000039
Kurt B. Kaisere866c812009-04-04 21:07:39 +000040HOST = '127.0.0.1' # python execution server on localhost loopback
41PORT = 0 # someday pass in host, port for remote debug capability
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000042
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000043# Override warnings module to write to warning_stream. Initialize to send IDLE
44# internal warnings to the console. ScriptBinding.check_syntax() will
45# temporarily redirect the stream to the shell window to display warnings when
46# checking user's code.
47global warning_stream
48warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000049try:
50 import warnings
51except ImportError:
52 pass
53else:
Benjamin Peterson206e3072008-10-19 14:07:49 +000054 def idle_showwarning(message, category, filename, lineno,
55 file=None, line=None):
Guilherme Polo1fff0082009-08-14 15:05:30 +000056 if file is None:
57 file = warning_stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000058 try:
Guilherme Polo1fff0082009-08-14 15:05:30 +000059 file.write(warnings.formatwarning(message, category, filename,
Senthil Kumaranaa90e7c2011-07-03 17:39:20 -070060 lineno, line=line))
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000061 except IOError:
62 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000063 warnings.showwarning = idle_showwarning
Guilherme Polo1fff0082009-08-14 15:05:30 +000064 def idle_formatwarning(message, category, filename, lineno, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000065 """Format warnings the IDLE way"""
66 s = "\nWarning (from warnings module):\n"
67 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polo1fff0082009-08-14 15:05:30 +000068 if line is None:
69 line = linecache.getline(filename, lineno)
70 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000071 if line:
72 s += " %s\n" % line
73 s += "%s: %s\n>>> " % (category.__name__, message)
74 return s
75 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000076
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000077def extended_linecache_checkcache(filename=None,
78 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000079 """Extend linecache.checkcache to preserve the <pyshell#...> entries
80
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000081 Rather than repeating the linecache code, patch it to save the
82 <pyshell#...> entries, call the original linecache.checkcache()
Guilherme Polo1fff0082009-08-14 15:05:30 +000083 (skipping them), and then restore the saved entries.
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000084
85 orig_checkcache is bound at definition time to the original
86 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000087 """
David Scherer7aced172000-08-15 01:13:23 +000088 cache = linecache.cache
89 save = {}
Guilherme Polo1fff0082009-08-14 15:05:30 +000090 for key in list(cache):
91 if key[:1] + key[-1:] == '<>':
92 save[key] = cache.pop(key)
93 orig_checkcache(filename)
David Scherer7aced172000-08-15 01:13:23 +000094 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000095
Kurt B. Kaiser81885592002-11-29 22:10:53 +000096# Patch linecache.checkcache():
97linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000098
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000099
David Scherer7aced172000-08-15 01:13:23 +0000100class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000101 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000102
David Scherer7aced172000-08-15 01:13:23 +0000103 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000104 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000105 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000106 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000107 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000108 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
109
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000110 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
111 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000112 # whenever a file is changed, restore breakpoints
113 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000114 def filename_changed_hook(old_hook=self.io.filename_change_hook,
115 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000116 self.restore_file_breaks()
117 old_hook()
118 self.io.set_filename_change_hook(filename_changed_hook)
119
Andrew Svetlovd1837672012-11-01 22:41:19 +0200120 rmenu_specs = [
121 ("Cut", "<<cut>>", "rmenu_check_cut"),
122 ("Copy", "<<copy>>", "rmenu_check_copy"),
123 ("Paste", "<<paste>>", "rmenu_check_paste"),
124 (None, None, None),
125 ("Set Breakpoint", "<<set-breakpoint-here>>", None),
126 ("Clear Breakpoint", "<<clear-breakpoint-here>>", None)
127 ]
David Scherer7aced172000-08-15 01:13:23 +0000128
Chui Teya2adb0f2002-11-04 22:14:54 +0000129 def set_breakpoint(self, lineno):
130 text = self.text
131 filename = self.io.filename
132 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
133 try:
134 i = self.breakpoints.index(lineno)
135 except ValueError: # only add if missing, i.e. do once
136 self.breakpoints.append(lineno)
137 try: # update the subprocess debugger
138 debug = self.flist.pyshell.interp.debugger
139 debug.set_breakpoint_here(filename, lineno)
140 except: # but debugger may not be active right now....
141 pass
142
David Scherer7aced172000-08-15 01:13:23 +0000143 def set_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()
David Scherer7aced172000-08-15 01:13:23 +0000148 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000149 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000150 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000151
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000152 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000153 text = self.text
154 filename = self.io.filename
155 if not filename:
156 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000157 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000158 lineno = int(float(text.index("insert")))
159 try:
160 self.breakpoints.remove(lineno)
161 except:
162 pass
163 text.tag_remove("BREAK", "insert linestart",\
164 "insert lineend +1char")
165 try:
166 debug = self.flist.pyshell.interp.debugger
167 debug.clear_breakpoint_here(filename, lineno)
168 except:
169 pass
170
171 def clear_file_breaks(self):
172 if self.breakpoints:
173 text = self.text
174 filename = self.io.filename
175 if not filename:
176 text.bell()
177 return
178 self.breakpoints = []
179 text.tag_remove("BREAK", "1.0", END)
180 try:
181 debug = self.flist.pyshell.interp.debugger
182 debug.clear_file_breaks(filename)
183 except:
184 pass
185
Chui Teya2adb0f2002-11-04 22:14:54 +0000186 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000187 "Save breakpoints when file is saved"
188 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
189 # be run. The breaks are saved at that time. If we introduce
190 # a temporary file save feature the save breaks functionality
191 # needs to be re-verified, since the breaks at the time the
192 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000193 # permanent save of the file. Currently, a break introduced
194 # after a save will be effective, but not persistent.
195 # This is necessary to keep the saved breaks synched with the
196 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000197 #
198 # Breakpoints are set as tagged ranges in the text. Certain
199 # kinds of edits cause these ranges to be deleted: Inserting
200 # or deleting a line just before a breakpoint, and certain
201 # deletions prior to a breakpoint. These issues need to be
202 # investigated and understood. It's not clear if they are
203 # Tk issues or IDLE issues, or whether they can actually
204 # be fixed. Since a modified file has to be saved before it is
205 # run, and since self.breakpoints (from which the subprocess
206 # debugger is loaded) is updated during the save, the visible
207 # breaks stay synched with the subprocess even if one of these
208 # unexpected breakpoint deletions occurs.
209 breaks = self.breakpoints
210 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000211 try:
Victor Stinner85c67722011-09-02 00:57:04 +0200212 with open(self.breakpointPath, "r") as fp:
213 lines = fp.readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000214 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000215 lines = []
Ned Deilyf505b742011-12-14 14:58:24 -0800216 try:
217 with open(self.breakpointPath, "w") as new_file:
218 for line in lines:
219 if not line.startswith(filename + '='):
220 new_file.write(line)
221 self.update_breakpoints()
222 breaks = self.breakpoints
223 if breaks:
224 new_file.write(filename + '=' + str(breaks) + '\n')
225 except IOError as err:
226 if not getattr(self.root, "breakpoint_error_displayed", False):
227 self.root.breakpoint_error_displayed = True
228 tkMessageBox.showerror(title='IDLE Error',
229 message='Unable to update breakpoint list:\n%s'
230 % str(err),
231 parent=self.text)
Chui Teya2adb0f2002-11-04 22:14:54 +0000232
233 def restore_file_breaks(self):
234 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000235 filename = self.io.filename
236 if filename is None:
237 return
Chui Tey69371d62002-11-04 23:39:45 +0000238 if os.path.isfile(self.breakpointPath):
Victor Stinner85c67722011-09-02 00:57:04 +0200239 with open(self.breakpointPath, "r") as fp:
240 lines = fp.readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000241 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000242 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000243 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000244 for breakpoint_linenumber in breakpoint_linenumbers:
245 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000246
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000247 def update_breakpoints(self):
248 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000249 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000250 ranges = text.tag_ranges("BREAK")
251 linenumber_list = self.ranges_to_linenumbers(ranges)
252 self.breakpoints = linenumber_list
253
254 def ranges_to_linenumbers(self, ranges):
255 lines = []
256 for index in range(0, len(ranges), 2):
Andrew Svetlov06c5c6d2012-07-31 19:48:00 +0300257 lineno = int(float(ranges[index].string))
258 end = int(float(ranges[index+1].string))
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000259 while lineno < end:
260 lines.append(lineno)
261 lineno += 1
262 return lines
263
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000264# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000265# def saved_change_hook(self):
266# "Extend base method - clear breaks if module is modified"
267# if not self.get_saved():
268# self.clear_file_breaks()
269# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000270
271 def _close(self):
272 "Extend base method - clear breaks when module is closed"
273 self.clear_file_breaks()
274 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000275
David Scherer7aced172000-08-15 01:13:23 +0000276
277class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000278 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000279
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000280 # override FileList's class variable, instances return PyShellEditorWindow
281 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000282 EditorWindow = PyShellEditorWindow
283
284 pyshell = None
285
286 def open_shell(self, event=None):
287 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000288 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000289 else:
290 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000291 if self.pyshell:
292 if not self.pyshell.begin():
293 return None
David Scherer7aced172000-08-15 01:13:23 +0000294 return self.pyshell
295
296
297class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000298 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000299
Steven M. Gavab77d3432002-03-02 07:16:21 +0000300 def __init__(self):
301 ColorDelegator.__init__(self)
302 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000303
304 def recolorize_main(self):
305 self.tag_remove("TODO", "1.0", "iomark")
306 self.tag_add("SYNC", "1.0", "iomark")
307 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000308
Steven M. Gavab77d3432002-03-02 07:16:21 +0000309 def LoadTagDefs(self):
310 ColorDelegator.LoadTagDefs(self)
311 theme = idleConf.GetOption('main','Theme','name')
312 self.tagdefs.update({
313 "stdin": {'background':None,'foreground':None},
314 "stdout": idleConf.GetHighlight(theme, "stdout"),
315 "stderr": idleConf.GetHighlight(theme, "stderr"),
316 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000317 })
David Scherer7aced172000-08-15 01:13:23 +0000318
Ned Deily8b2a56b2012-05-31 09:17:29 -0700319 def removecolors(self):
320 # Don't remove shell color tags before "iomark"
321 for tag in self.tagdefs:
322 self.tag_remove(tag, "iomark", "end")
323
David Scherer7aced172000-08-15 01:13:23 +0000324class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000325 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000326
327 def insert(self, index, chars, tags=None):
328 try:
329 if self.delegate.compare(index, "<", "iomark"):
330 self.delegate.bell()
331 return
332 except TclError:
333 pass
334 UndoDelegator.insert(self, index, chars, tags)
335
336 def delete(self, index1, index2=None):
337 try:
338 if self.delegate.compare(index1, "<", "iomark"):
339 self.delegate.bell()
340 return
341 except TclError:
342 pass
343 UndoDelegator.delete(self, index1, index2)
344
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000345
346class MyRPCClient(rpc.RPCClient):
347
348 def handle_EOF(self):
349 "Override the base class - just re-raise EOFError"
350 raise EOFError
351
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000352
David Scherer7aced172000-08-15 01:13:23 +0000353class ModifiedInterpreter(InteractiveInterpreter):
354
355 def __init__(self, tkconsole):
356 self.tkconsole = tkconsole
357 locals = sys.modules['__main__'].__dict__
358 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000359 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000360 self.restarting = False
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000361 self.subprocess_arglist = None
362 self.port = PORT
Ned Deily7aff4512011-10-30 20:01:35 -0700363 self.original_compiler_flags = self.compile.compiler.flags
David Scherer7aced172000-08-15 01:13:23 +0000364
Chui Tey5d2af632002-05-26 13:36:41 +0000365 rpcclt = None
Ned Deilye5cad232011-08-02 18:47:13 -0700366 rpcsubproc = None
Chui Tey5d2af632002-05-26 13:36:41 +0000367
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000368 def spawn_subprocess(self):
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000369 if self.subprocess_arglist is None:
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000370 self.subprocess_arglist = self.build_subprocess_arglist()
Ned Deilye5cad232011-08-02 18:47:13 -0700371 self.rpcsubproc = subprocess.Popen(self.subprocess_arglist)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000372
Tony Lowndsf53dec22002-12-20 04:24:43 +0000373 def build_subprocess_arglist(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000374 assert (self.port!=0), (
375 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000376 w = ['-W' + s for s in sys.warnoptions]
377 # Maybe IDLE is installed and is being accessed via sys.path,
378 # or maybe it's not installed and the idle.py script is being
379 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000380 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
381 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000382 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000383 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000384 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000385 command = "__import__('run').main(%r)" % (del_exitf,)
Ned Deilye5cad232011-08-02 18:47:13 -0700386 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000387
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000388 def start_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000389 addr = (HOST, self.port)
390 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000391 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000392 time.sleep(i)
393 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000394 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000395 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000396 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000397 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000398 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000399 self.display_port_binding_error()
400 return None
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000401 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
402 self.port = self.rpcclt.listening_sock.getsockname()[1]
403 # if PORT was not 0, probably working with a remote execution server
404 if PORT != 0:
405 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
406 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
407 # on Windows since the implementation allows two active sockets on
408 # the same address!
409 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
410 socket.SO_REUSEADDR, 1)
411 self.spawn_subprocess()
412 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000413 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000414 self.rpcclt.listening_sock.settimeout(10)
415 try:
416 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000417 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000418 self.display_no_subprocess_error()
419 return None
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200420 self.rpcclt.register("console", self.tkconsole)
421 self.rpcclt.register("stdin", self.tkconsole.stdin)
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000422 self.rpcclt.register("stdout", self.tkconsole.stdout)
423 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000424 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000425 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000426 self.rpcclt.register("interp", self)
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500427 self.transfer_path(with_cwd=True)
Chui Tey5d2af632002-05-26 13:36:41 +0000428 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000429 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000430
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500431 def restart_subprocess(self, with_cwd=False):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000432 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000433 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000434 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000435 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000436 debug = self.getdebugger()
437 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000438 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000439 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000440 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
441 except:
442 pass
443 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000444 self.rpcclt.close()
Ned Deilye5cad232011-08-02 18:47:13 -0700445 self.terminate_subprocess()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000446 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000447 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000448 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000449 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000450 try:
451 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000452 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000453 self.display_no_subprocess_error()
454 return None
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500455 self.transfer_path(with_cwd=with_cwd)
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000456 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000457 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000458 if was_executing:
459 console.write('\n')
460 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000461 halfbar = ((int(console.width) - 16) // 2) * '='
462 console.write(halfbar + ' RESTART ' + halfbar)
463 console.text.mark_set("restart", "end-1c")
464 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000465 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000466 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000467 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000468 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000469 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000470 # reload remote debugger breakpoints for all PyShellEditWindows
471 debug.load_breakpoints()
Ned Deily7aff4512011-10-30 20:01:35 -0700472 self.compile.compiler.flags = self.original_compiler_flags
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000473 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000474 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000475
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000476 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000477 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000478
479 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000480 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000481
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000482 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000483 try:
484 self.rpcclt.close()
485 except AttributeError: # no socket
486 pass
Ned Deilye5cad232011-08-02 18:47:13 -0700487 self.terminate_subprocess()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000488 self.tkconsole.executing = False
489 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000490
Ned Deilye5cad232011-08-02 18:47:13 -0700491 def terminate_subprocess(self):
492 "Make sure subprocess is terminated"
493 try:
494 self.rpcsubproc.kill()
495 except OSError:
496 # process already terminated
497 return
498 else:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000499 try:
Ned Deilye5cad232011-08-02 18:47:13 -0700500 self.rpcsubproc.wait()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000501 except OSError:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000502 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000503
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500504 def transfer_path(self, with_cwd=False):
505 if with_cwd: # Issue 13506
506 path = [''] # include Current Working Directory
507 path.extend(sys.path)
508 else:
509 path = sys.path
Terry Jan Reedy4d82ade2012-01-31 02:57:29 -0500510
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000511 self.runcommand("""if 1:
512 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000513 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000514 del _sys
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500515 \n""" % (path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000516
Chui Tey5d2af632002-05-26 13:36:41 +0000517 active_seq = None
518
519 def poll_subprocess(self):
520 clt = self.rpcclt
521 if clt is None:
522 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000523 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000524 response = clt.pollresponse(self.active_seq, wait=0.05)
525 except (EOFError, IOError, KeyboardInterrupt):
526 # lost connection or subprocess terminated itself, restart
527 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000528 if self.tkconsole.closing:
529 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000530 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000531 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000532 if response:
533 self.tkconsole.resetoutput()
534 self.active_seq = None
535 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000536 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000537 if how == "OK":
538 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000539 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000540 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000541 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
542 self.remote_stack_viewer()
543 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000544 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000545 print(errmsg, what, file=sys.__stderr__)
546 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000547 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000548 try:
549 self.tkconsole.endexecuting()
550 except AttributeError: # shell may have closed
551 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000552 # Reschedule myself
553 if not self.tkconsole.closing:
554 self.tkconsole.text.after(self.tkconsole.pollinterval,
555 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000556
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000557 debugger = None
558
559 def setdebugger(self, debugger):
560 self.debugger = debugger
561
562 def getdebugger(self):
563 return self.debugger
564
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000565 def open_remote_stack_viewer(self):
566 """Initiate the remote stack viewer from a separate thread.
567
568 This method is called from the subprocess, and by returning from this
569 method we allow the subprocess to unblock. After a bit the shell
570 requests the subprocess to open the remote stack viewer which returns a
Ezio Melotti60861182010-07-23 16:48:22 +0000571 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000572 the RPC mechanism.
573
574 """
575 self.tkconsole.text.after(300, self.remote_stack_viewer)
576 return
577
Chui Tey5d2af632002-05-26 13:36:41 +0000578 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000579 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000580 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000581 if oid is None:
582 self.tkconsole.root.bell()
583 return
584 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000585 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000586 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000587 theme = idleConf.GetOption('main','Theme','name')
588 background = idleConf.GetHighlight(theme, 'normal')['background']
589 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000590 sc.frame.pack(expand=1, fill="both")
591 node = TreeNode(sc.canvas, None, item)
592 node.expand()
593 # XXX Should GC the remote tree when closing the window
594
David Scherer7aced172000-08-15 01:13:23 +0000595 gid = 0
596
597 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000598 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000599 filename = self.stuffsource(source)
600 self.execfile(filename, source)
601
602 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000603 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000604 if source is None:
Victor Stinner979482a2011-09-02 01:00:40 +0200605 with tokenize.open(filename) as fp:
Victor Stinner85c67722011-09-02 00:57:04 +0200606 source = fp.read()
David Scherer7aced172000-08-15 01:13:23 +0000607 try:
608 code = compile(source, filename, "exec")
609 except (OverflowError, SyntaxError):
610 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000611 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000612 print('*** Error in script or command!\n', file=tkerr)
613 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000614 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000615 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000616 else:
617 self.runcode(code)
618
619 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000620 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000621 filename = self.stuffsource(source)
622 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000623 self.save_warnings_filters = warnings.filters[:]
624 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000625 # at the moment, InteractiveInterpreter expects str
626 assert isinstance(source, str)
627 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000628 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000629 # try:
630 # source = source.encode(IOBinding.encoding)
631 # except UnicodeError:
632 # self.tkconsole.resetoutput()
633 # self.write("Unsupported characters in input\n")
634 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000635 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000636 # InteractiveInterpreter.runsource() calls its runcode() method,
637 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000638 return InteractiveInterpreter.runsource(self, source, filename)
639 finally:
640 if self.save_warnings_filters is not None:
641 warnings.filters[:] = self.save_warnings_filters
642 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000643
644 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000645 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000646 filename = "<pyshell#%d>" % self.gid
647 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000648 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000649 linecache.cache[filename] = len(source)+1, 0, lines, filename
650 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000651
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000652 def prepend_syspath(self, filename):
653 "Prepend sys.path with file's directory if not already included"
654 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000655 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000656 import sys as _sys
657 from os.path import dirname as _dirname
658 _dir = _dirname(_filename)
659 if not _dir in _sys.path:
660 _sys.path.insert(0, _dir)
661 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000662 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000663
David Scherer7aced172000-08-15 01:13:23 +0000664 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000665 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000666
667 Color the offending position instead of printing it and pointing at it
668 with a caret.
669
670 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000671 tkconsole = self.tkconsole
672 text = tkconsole.text
673 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000674 type, value, tb = sys.exc_info()
Ned Deily79746422011-09-14 14:49:14 -0700675 msg = getattr(value, 'msg', '') or value or "<no detail available>"
676 lineno = getattr(value, 'lineno', '') or 1
677 offset = getattr(value, 'offset', '') or 0
Guido van Rossum33d26892007-08-05 15:29:28 +0000678 if offset == 0:
679 lineno += 1 #mark end of offending line
680 if lineno == 1:
681 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000682 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000683 pos = "iomark linestart + %d lines + %d chars" % \
684 (lineno-1, offset-1)
685 tkconsole.colorize_syntax_error(text, pos)
686 tkconsole.resetoutput()
687 self.write("SyntaxError: %s\n" % msg)
688 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000689
690 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000691 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000692 self.tkconsole.resetoutput()
693 self.checklinecache()
694 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000695 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
696 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000697
698 def checklinecache(self):
699 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000700 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000701 if key[:1] + key[-1:] != "<>":
702 del c[key]
703
Chui Tey5d2af632002-05-26 13:36:41 +0000704 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000705 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000706 # The code better not raise an exception!
707 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000708 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000709 return 0
710 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000711 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000712 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000713 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000714 return 1
715
David Scherer7aced172000-08-15 01:13:23 +0000716 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000717 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000718 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000719 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000720 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000721 if self.save_warnings_filters is not None:
722 warnings.filters[:] = self.save_warnings_filters
723 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000724 debugger = self.debugger
725 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000726 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000727 if not debugger and self.rpcclt is not None:
728 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
729 (code,), {})
730 elif debugger:
731 debugger.run(code, self.locals)
732 else:
733 exec(code, self.locals)
734 except SystemExit:
735 if not self.tkconsole.closing:
736 if tkMessageBox.askyesno(
737 "Exit?",
738 "Do you want to exit altogether?",
739 default="yes",
740 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000741 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000742 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000743 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000744 else:
745 raise
746 except:
747 if use_subprocess:
748 print("IDLE internal error in runcode()",
749 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000750 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000751 self.tkconsole.endexecuting()
752 else:
753 if self.tkconsole.canceled:
754 self.tkconsole.canceled = False
755 print("KeyboardInterrupt", file=self.tkconsole.stderr)
756 else:
757 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000758 finally:
759 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000760 try:
761 self.tkconsole.endexecuting()
762 except AttributeError: # shell may have closed
763 pass
David Scherer7aced172000-08-15 01:13:23 +0000764
765 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000766 "Override base class method"
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +0200767 return self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000768
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000769 def display_port_binding_error(self):
770 tkMessageBox.showerror(
771 "Port Binding Error",
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000772 "IDLE can't bind to a TCP/IP port, which is necessary to "
773 "communicate with its Python execution server. This might be "
774 "because no networking is installed on this computer. "
775 "Run IDLE with the -n command line switch to start without a "
776 "subprocess and refer to Help/IDLE Help 'Running without a "
777 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000778 master=self.tkconsole.text)
779
780 def display_no_subprocess_error(self):
781 tkMessageBox.showerror(
782 "Subprocess Startup Error",
783 "IDLE's subprocess didn't make connection. Either IDLE can't "
784 "start a subprocess or personal firewall software is blocking "
785 "the connection.",
786 master=self.tkconsole.text)
787
788 def display_executing_dialog(self):
789 tkMessageBox.showerror(
790 "Already executing",
791 "The Python Shell window is already executing a command; "
792 "please wait until it is finished.",
793 master=self.tkconsole.text)
794
795
David Scherer7aced172000-08-15 01:13:23 +0000796class PyShell(OutputWindow):
797
798 shell_title = "Python Shell"
799
800 # Override classes
801 ColorDelegator = ModifiedColorDelegator
802 UndoDelegator = ModifiedUndoDelegator
803
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000804 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000805 menu_specs = [
806 ("file", "_File"),
807 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000808 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000809 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000810 ("windows", "_Windows"),
811 ("help", "_Help"),
812 ]
David Scherer7aced172000-08-15 01:13:23 +0000813
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000814 if macosxSupport.runningAsOSXApp():
815 del menu_specs[-3]
816 menu_specs[-2] = ("windows", "_Window")
817
818
David Scherer7aced172000-08-15 01:13:23 +0000819 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000820 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000821
822 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000823 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000824 ms = self.menu_specs
825 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000826 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000827 self.interp = ModifiedInterpreter(self)
828 if flist is None:
829 root = Tk()
830 fixwordbreaks(root)
831 root.withdraw()
832 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000833 #
David Scherer7aced172000-08-15 01:13:23 +0000834 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000835 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000836## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
837 self.usetabs = True
838 # indentwidth must be 8 when using tabs. See note in EditorWindow:
839 self.indentwidth = 8
840 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000841 #
David Scherer7aced172000-08-15 01:13:23 +0000842 text = self.text
843 text.configure(wrap="char")
844 text.bind("<<newline-and-indent>>", self.enter_callback)
845 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
846 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000847 text.bind("<<end-of-file>>", self.eof_callback)
848 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000849 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000850 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8a78cad2007-12-13 03:38:16 +0000851 self.color = color = self.ColorDelegator()
852 self.per.insertfilter(color)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000853 if use_subprocess:
854 text.bind("<<view-restart>>", self.view_restart_mark)
855 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000856 #
David Scherer7aced172000-08-15 01:13:23 +0000857 self.save_stdout = sys.stdout
858 self.save_stderr = sys.stderr
859 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000860 from idlelib import IOBinding
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200861 self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
862 self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
863 self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
864 self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000865 if not use_subprocess:
866 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000867 sys.stderr = self.stderr
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200868 sys.stdin = self.stdin
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000869 try:
870 # page help() text to shell.
871 import pydoc # import must be done here to capture i/o rebinding.
872 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
873 pydoc.pager = pydoc.plainpager
874 except:
875 sys.stderr = sys.__stderr__
876 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000877 #
David Scherer7aced172000-08-15 01:13:23 +0000878 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000879 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000880 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000881
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000882 def get_standard_extension_names(self):
883 return idleConf.GetExtensions(shell_only=True)
884
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000885 reading = False
886 executing = False
887 canceled = False
888 endoffile = False
889 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000890
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000891 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000892 global warning_stream
893 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000894
895 def get_warning_stream(self):
896 return warning_stream
897
David Scherer7aced172000-08-15 01:13:23 +0000898 def toggle_debugger(self, event=None):
899 if self.executing:
900 tkMessageBox.showerror("Don't debug now",
901 "You can only toggle the debugger when idle",
902 master=self.text)
903 self.set_debugger_indicator()
904 return "break"
905 else:
906 db = self.interp.getdebugger()
907 if db:
908 self.close_debugger()
909 else:
910 self.open_debugger()
911
912 def set_debugger_indicator(self):
913 db = self.interp.getdebugger()
914 self.setvar("<<toggle-debugger>>", not not db)
915
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000916 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000917 pass # All we need is the variable
918
919 def close_debugger(self):
920 db = self.interp.getdebugger()
921 if db:
922 self.interp.setdebugger(None)
923 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000924 if self.interp.rpcclt:
925 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000926 self.resetoutput()
927 self.console.write("[DEBUG OFF]\n")
928 sys.ps1 = ">>> "
929 self.showprompt()
930 self.set_debugger_indicator()
931
932 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000933 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000934 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
935 self)
936 else:
937 dbg_gui = Debugger.Debugger(self)
938 self.interp.setdebugger(dbg_gui)
939 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000940 sys.ps1 = "[DEBUG ON]\n>>> "
941 self.showprompt()
942 self.set_debugger_indicator()
943
David Scherer7aced172000-08-15 01:13:23 +0000944 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000945 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000946 self.resetoutput()
947 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000948
949 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000950 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000951 self.executing = 0
952 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000953 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000954
955 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000956 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000957 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000958 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000959 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000960 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000961 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000962 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000963 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000964 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000965 if self.reading:
966 self.top.quit()
967 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000968 self.closing = True
969 # Wait for poll_subprocess() rescheduling to stop
970 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000971
972 def close2(self):
973 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000974
975 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000976 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000977 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000978 if use_subprocess:
979 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000980 # Restore std streams
981 sys.stdout = self.save_stdout
982 sys.stderr = self.save_stderr
983 sys.stdin = self.save_stdin
984 # Break cycles
985 self.interp = None
986 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000987 self.flist.pyshell = None
988 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000989 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000990
991 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000992 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000993 return True
David Scherer7aced172000-08-15 01:13:23 +0000994
995 def short_title(self):
996 return self.shell_title
997
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000998 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000999 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001000
David Scherer7aced172000-08-15 01:13:23 +00001001 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +00001002 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +00001003 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001004 if use_subprocess:
1005 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001006 client = self.interp.start_subprocess()
1007 if not client:
1008 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001009 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001010 else:
1011 nosub = "==== No Subprocess ===="
Raymond Hettingera2a8e8b2009-01-27 00:28:36 +00001012 self.write("Python %s on %s\n%s\n%s" %
1013 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +00001014 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +00001015 import tkinter
1016 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001017 return True
David Scherer7aced172000-08-15 01:13:23 +00001018
1019 def readline(self):
1020 save = self.reading
1021 try:
1022 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001023 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001024 finally:
1025 self.reading = save
1026 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001027 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1028 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +00001029 self.resetoutput()
1030 if self.canceled:
1031 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001032 if not use_subprocess:
1033 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001034 if self.endoffile:
1035 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001036 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001037 return line
1038
1039 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001040 return True
David Scherer7aced172000-08-15 01:13:23 +00001041
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001042 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001043 try:
1044 if self.text.compare("sel.first", "!=", "sel.last"):
1045 return # Active selection -- always use default binding
1046 except:
1047 pass
1048 if not (self.executing or self.reading):
1049 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001050 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001051 self.showprompt()
1052 return "break"
1053 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001054 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001055 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001056 if self.interp.getdebugger():
1057 self.interp.restart_subprocess()
1058 else:
1059 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001060 if self.reading:
1061 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001062 return "break"
1063
1064 def eof_callback(self, event):
1065 if self.executing and not self.reading:
1066 return # Let the default binding (delete next char) take over
1067 if not (self.text.compare("iomark", "==", "insert") and
1068 self.text.compare("insert", "==", "end-1c")):
1069 return # Let the default binding (delete next char) take over
1070 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001071 self.resetoutput()
1072 self.close()
1073 else:
1074 self.canceled = 0
1075 self.endoffile = 1
1076 self.top.quit()
1077 return "break"
1078
David Scherer7aced172000-08-15 01:13:23 +00001079 def linefeed_callback(self, event):
1080 # Insert a linefeed without entering anything (still autoindented)
1081 if self.reading:
1082 self.text.insert("insert", "\n")
1083 self.text.see("insert")
1084 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001085 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001086 return "break"
1087
1088 def enter_callback(self, event):
1089 if self.executing and not self.reading:
1090 return # Let the default binding (insert '\n') take over
1091 # If some text is selected, recall the selection
1092 # (but only if this before the I/O mark)
1093 try:
1094 sel = self.text.get("sel.first", "sel.last")
1095 if sel:
1096 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001097 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001098 return "break"
1099 except:
1100 pass
1101 # If we're strictly before the line containing iomark, recall
1102 # the current line, less a leading prompt, less leading or
1103 # trailing whitespace
1104 if self.text.compare("insert", "<", "iomark linestart"):
1105 # Check if there's a relevant stdin range -- if so, use it
1106 prev = self.text.tag_prevrange("stdin", "insert")
1107 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001108 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001109 return "break"
1110 next = self.text.tag_nextrange("stdin", "insert")
1111 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001112 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001113 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001114 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001115 indices = self.text.tag_nextrange("console", "insert linestart")
1116 if indices and \
1117 self.text.compare(indices[0], "<=", "insert linestart"):
1118 self.recall(self.text.get(indices[1], "insert lineend"), event)
1119 else:
1120 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001121 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001122 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001123 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001124 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001125 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001126 # If we're in the current input and there's only whitespace
1127 # beyond the cursor, erase that whitespace first
1128 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001129 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001130 self.text.delete("insert", "end-1c")
1131 # If we're in the current input before its last line,
1132 # insert a newline right at the insert point
1133 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001134 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001135 return "break"
1136 # We're in the last line; append a newline and submit it
1137 self.text.mark_set("insert", "end-1c")
1138 if self.reading:
1139 self.text.insert("insert", "\n")
1140 self.text.see("insert")
1141 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001142 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001143 self.text.tag_add("stdin", "iomark", "end-1c")
1144 self.text.update_idletasks()
1145 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001146 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001147 else:
1148 self.runit()
1149 return "break"
1150
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001151 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001152 # remove leading and trailing empty or whitespace lines
1153 s = re.sub(r'^\s*\n', '' , s)
1154 s = re.sub(r'\n\s*$', '', s)
1155 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001156 self.text.undo_block_start()
1157 try:
1158 self.text.tag_remove("sel", "1.0", "end")
1159 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001160 prefix = self.text.get("insert linestart", "insert")
1161 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001162 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001163 prefix = self.text.get("insert linestart", "insert")
1164 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001165 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001166 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1167 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001168 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001169 if line.startswith(orig_base_indent):
1170 # replace orig base indentation with new indentation
1171 line = new_base_indent + line[len(orig_base_indent):]
1172 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001173 finally:
1174 self.text.see("insert")
1175 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001176
1177 def runit(self):
1178 line = self.text.get("iomark", "end-1c")
1179 # Strip off last newline and surrounding whitespace.
1180 # (To allow you to hit return twice to end a statement.)
1181 i = len(line)
1182 while i > 0 and line[i-1] in " \t":
1183 i = i-1
1184 if i > 0 and line[i-1] == "\n":
1185 i = i-1
1186 while i > 0 and line[i-1] in " \t":
1187 i = i-1
1188 line = line[:i]
1189 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001190
David Scherer7aced172000-08-15 01:13:23 +00001191 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001192 if self.interp.rpcclt:
1193 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001194 try:
1195 sys.last_traceback
1196 except:
1197 tkMessageBox.showerror("No stack trace",
1198 "There is no stack trace yet.\n"
1199 "(sys.last_traceback is not defined)",
1200 master=self.text)
1201 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001202 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001203 sv = StackBrowser(self.root, self.flist)
1204
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001205 def view_restart_mark(self, event=None):
1206 self.text.see("iomark")
1207 self.text.see("restart")
1208
1209 def restart_shell(self, event=None):
Terry Jan Reedyda4c4672012-01-31 02:26:32 -05001210 "Callback for Run/Restart Shell Cntl-F6"
1211 self.interp.restart_subprocess(with_cwd=True)
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001212
David Scherer7aced172000-08-15 01:13:23 +00001213 def showprompt(self):
1214 self.resetoutput()
1215 try:
1216 s = str(sys.ps1)
1217 except:
1218 s = ""
1219 self.console.write(s)
1220 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001221 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001222 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001223
1224 def resetoutput(self):
1225 source = self.text.get("iomark", "end-1c")
1226 if self.history:
1227 self.history.history_store(source)
1228 if self.text.get("end-2c") != "\n":
1229 self.text.insert("end-1c", "\n")
1230 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001231 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001232
1233 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001234 try:
1235 self.text.mark_gravity("iomark", "right")
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +02001236 count = OutputWindow.write(self, s, tags, "iomark")
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001237 self.text.mark_gravity("iomark", "left")
1238 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001239 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1240 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001241 if self.canceled:
1242 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001243 if not use_subprocess:
1244 raise KeyboardInterrupt
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +02001245 return count
David Scherer7aced172000-08-15 01:13:23 +00001246
Andrew Svetlovd1837672012-11-01 22:41:19 +02001247 def rmenu_check_cut(self):
1248 try:
1249 if self.text.compare('sel.first', '<', 'iomark'):
1250 return 'disabled'
1251 except TclError: # no selection, so the index 'sel.first' doesn't exist
1252 return 'disabled'
1253 return super().rmenu_check_cut()
1254
1255 def rmenu_check_paste(self):
1256 if self.text.compare('insert','<','iomark'):
1257 return 'disabled'
1258 return super().rmenu_check_paste()
1259
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001260class PseudoFile(io.TextIOBase):
David Scherer7aced172000-08-15 01:13:23 +00001261
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001262 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001263 self.shell = shell
1264 self.tags = tags
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001265 self._encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001266
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001267 @property
1268 def encoding(self):
1269 return self._encoding
David Scherer7aced172000-08-15 01:13:23 +00001270
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001271 @property
1272 def name(self):
1273 return '<%s>' % self.tags
David Scherer7aced172000-08-15 01:13:23 +00001274
1275 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001276 return True
David Scherer7aced172000-08-15 01:13:23 +00001277
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001278
1279class PseudoOutputFile(PseudoFile):
1280
1281 def writable(self):
1282 return True
Martin v. Löwisc882b7c2012-07-25 10:47:20 +02001283
1284 def write(self, s):
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001285 if self.closed:
1286 raise ValueError("write to closed file")
1287 if not isinstance(s, str):
1288 raise TypeError('must be str, not ' + type(s).__name__)
1289 return self.shell.write(s, self.tags)
1290
1291
1292class PseudoInputFile(PseudoFile):
1293
1294 def __init__(self, shell, tags, encoding=None):
1295 PseudoFile.__init__(self, shell, tags, encoding)
1296 self._line_buffer = ''
1297
1298 def readable(self):
1299 return True
1300
1301 def read(self, size=-1):
1302 if self.closed:
1303 raise ValueError("read from closed file")
1304 if size is None:
1305 size = -1
1306 elif not isinstance(size, int):
1307 raise TypeError('must be int, not ' + type(size).__name__)
1308 result = self._line_buffer
1309 self._line_buffer = ''
1310 if size < 0:
1311 while True:
1312 line = self.shell.readline()
1313 if not line: break
1314 result += line
1315 else:
1316 while len(result) < size:
1317 line = self.shell.readline()
1318 if not line: break
1319 result += line
1320 self._line_buffer = result[size:]
1321 result = result[:size]
1322 return result
1323
1324 def readline(self, size=-1):
1325 if self.closed:
1326 raise ValueError("read from closed file")
1327 if size is None:
1328 size = -1
1329 elif not isinstance(size, int):
1330 raise TypeError('must be int, not ' + type(size).__name__)
1331 line = self._line_buffer or self.shell.readline()
1332 if size < 0:
1333 size = len(line)
1334 self._line_buffer = line[size:]
1335 return line[:size]
Martin v. Löwisc882b7c2012-07-25 10:47:20 +02001336
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001337
David Scherer7aced172000-08-15 01:13:23 +00001338usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001339
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001340USAGE: idle [-deins] [-t title] [file]*
1341 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1342 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001343
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001344 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001345 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001346
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001347The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001348
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001349 -e open an edit window
1350 -i open a shell window
1351
1352The following options imply -i and will open a shell:
1353
1354 -c cmd run the command in a shell, or
1355 -r file run script from file
1356
1357 -d enable the debugger
1358 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1359 -t title set title of shell window
1360
1361A default edit window will be bypassed when -c, -r, or - are used.
1362
1363[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1364
1365Examples:
1366
1367idle
1368 Open an edit window or shell depending on IDLE's configuration.
1369
1370idle foo.py foobar.py
1371 Edit the files, also open a shell if configured to start with shell.
1372
1373idle -est "Baz" foo.py
1374 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1375 window with the title "Baz".
1376
Neal Norwitz752abd02008-05-13 04:55:24 +00001377idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001378 Open a shell window and run the command, passing "-c" in sys.argv[0]
1379 and "foo" in sys.argv[1].
1380
1381idle -d -s -r foo.py "Hello World"
1382 Open a shell window, run a startup script, enable the debugger, and
1383 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1384 sys.argv[1].
1385
Neal Norwitz752abd02008-05-13 04:55:24 +00001386echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001387 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1388 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001389"""
1390
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001391def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001392 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001393
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001394 use_subprocess = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001395 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001396 enable_edit = False
1397 debug = False
1398 cmd = None
1399 script = None
1400 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001401 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001402 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001403 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001404 sys.stderr.write("Error: %s\n" % str(msg))
1405 sys.stderr.write(usage_msg)
1406 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001407 for o, a in opts:
1408 if o == '-c':
1409 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001410 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001411 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001412 debug = True
1413 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001414 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001415 enable_edit = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001416 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001417 if o == '-h':
1418 sys.stdout.write(usage_msg)
1419 sys.exit()
1420 if o == '-i':
1421 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001422 if o == '-n':
1423 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001424 if o == '-r':
1425 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001426 if os.path.isfile(script):
1427 pass
1428 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001429 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001430 sys.exit()
1431 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001432 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001433 startup = True
1434 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001435 if o == '-t':
1436 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001437 enable_shell = True
1438 if args and args[0] == '-':
1439 cmd = sys.stdin.read()
1440 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001441 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001442 for i in range(len(sys.path)):
1443 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001444 if args and args[0] == '-':
1445 sys.argv = [''] + args[1:]
1446 elif cmd:
1447 sys.argv = ['-c'] + args
1448 elif script:
1449 sys.argv = [script] + args
1450 elif args:
1451 enable_edit = True
1452 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001453 for filename in args:
1454 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001455 for dir in pathx:
1456 dir = os.path.abspath(dir)
1457 if not dir in sys.path:
1458 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001459 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001460 dir = os.getcwd()
1461 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001462 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001463 # check the IDLE settings configuration (but command line overrides)
1464 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001465 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001466 enable_edit = enable_edit or edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001467 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001468 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001469
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001470 fixwordbreaks(root)
1471 root.withdraw()
1472 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001473 macosxSupport.setupApp(root, flist)
1474
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001475 if enable_edit:
1476 if not (cmd or script):
Andrew Svetlov0f71f442012-03-21 13:23:41 +02001477 for filename in args[:]:
1478 if flist.open(filename) is None:
1479 # filename is a directory actually, disconsider it
1480 args.remove(filename)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001481 if not args:
1482 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001483 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001484 shell = flist.open_shell()
1485 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001486 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001487
1488 if macosxSupport.runningAsOSXApp() and flist.dict:
1489 # On OSX: when the user has double-clicked on a file that causes
1490 # IDLE to be launched the shell window will open just in front of
1491 # the file she wants to see. Lower the interpreter window when
1492 # there are open files.
1493 shell.top.lower()
1494
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001495 shell = flist.pyshell
1496 # handle remaining options:
1497 if debug:
1498 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001499 if startup:
1500 filename = os.environ.get("IDLESTARTUP") or \
1501 os.environ.get("PYTHONSTARTUP")
1502 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001503 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001504 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001505 shell.interp.runcommand("""if 1:
1506 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001507 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001508 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001509 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001510 if cmd:
1511 shell.interp.execsource(cmd)
1512 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001513 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001514 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001515
Ned Deily4ce92b22011-01-15 04:37:12 +00001516 # Check for problematic OS X Tk versions and print a warning message
1517 # in the IDLE shell window; this is less intrusive than always opening
1518 # a separate window.
1519 tkversionwarning = macosxSupport.tkVersionWarning(root)
1520 if tkversionwarning:
1521 shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
1522
Terry Jan Reedycd6b8c62012-05-26 20:23:45 -04001523 while flist.inversedict: # keep IDLE running while files are open.
1524 root.mainloop()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001525 root.destroy()
1526
David Scherer7aced172000-08-15 01:13:23 +00001527if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001528 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001529 main()