blob: d15034f9299e25a507bff9c4fbe9920a2d3a46b9 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
David Scherer7aced172000-08-15 01:13:23 +00002
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
Ned Deilye5cad232011-08-02 18:47:13 -070013import subprocess
David Scherer7aced172000-08-15 01:13:23 +000014
15import linecache
16from code import InteractiveInterpreter
17
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000018try:
Georg Brandl14fc4272008-05-17 18:39:55 +000019 from tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000020except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000021 print("** IDLE can't import Tkinter. " \
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000022 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000023 sys.exit(1)
Georg Brandl14fc4272008-05-17 18:39:55 +000024import tkinter.messagebox as tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000025
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000026from idlelib.EditorWindow import EditorWindow, fixwordbreaks
27from idlelib.FileList import FileList
28from idlelib.ColorDelegator import ColorDelegator
29from idlelib.UndoDelegator import UndoDelegator
30from idlelib.OutputWindow import OutputWindow
31from idlelib.configHandler import idleConf
32from idlelib import idlever
33from idlelib import rpc
34from idlelib import Debugger
35from idlelib import RemoteDebugger
36from idlelib import macosxSupport
Chui Tey5d2af632002-05-26 13:36:41 +000037
Kurt B. Kaisere866c812009-04-04 21:07:39 +000038HOST = '127.0.0.1' # python execution server on localhost loopback
39PORT = 0 # someday pass in host, port for remote debug capability
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000040
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000041# Override warnings module to write to warning_stream. Initialize to send IDLE
42# internal warnings to the console. ScriptBinding.check_syntax() will
43# temporarily redirect the stream to the shell window to display warnings when
44# checking user's code.
45global warning_stream
46warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000047try:
48 import warnings
49except ImportError:
50 pass
51else:
Benjamin Peterson206e3072008-10-19 14:07:49 +000052 def idle_showwarning(message, category, filename, lineno,
53 file=None, line=None):
Guilherme Polo1fff0082009-08-14 15:05:30 +000054 if file is None:
55 file = warning_stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000056 try:
Guilherme Polo1fff0082009-08-14 15:05:30 +000057 file.write(warnings.formatwarning(message, category, filename,
Senthil Kumaranaa90e7c2011-07-03 17:39:20 -070058 lineno, line=line))
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000059 except IOError:
60 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000061 warnings.showwarning = idle_showwarning
Guilherme Polo1fff0082009-08-14 15:05:30 +000062 def idle_formatwarning(message, category, filename, lineno, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000063 """Format warnings the IDLE way"""
64 s = "\nWarning (from warnings module):\n"
65 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polo1fff0082009-08-14 15:05:30 +000066 if line is None:
67 line = linecache.getline(filename, lineno)
68 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000069 if line:
70 s += " %s\n" % line
71 s += "%s: %s\n>>> " % (category.__name__, message)
72 return s
73 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000074
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000075def extended_linecache_checkcache(filename=None,
76 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077 """Extend linecache.checkcache to preserve the <pyshell#...> entries
78
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000079 Rather than repeating the linecache code, patch it to save the
80 <pyshell#...> entries, call the original linecache.checkcache()
Guilherme Polo1fff0082009-08-14 15:05:30 +000081 (skipping them), and then restore the saved entries.
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000082
83 orig_checkcache is bound at definition time to the original
84 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000085 """
David Scherer7aced172000-08-15 01:13:23 +000086 cache = linecache.cache
87 save = {}
Guilherme Polo1fff0082009-08-14 15:05:30 +000088 for key in list(cache):
89 if key[:1] + key[-1:] == '<>':
90 save[key] = cache.pop(key)
91 orig_checkcache(filename)
David Scherer7aced172000-08-15 01:13:23 +000092 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000093
Kurt B. Kaiser81885592002-11-29 22:10:53 +000094# Patch linecache.checkcache():
95linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000096
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000097
David Scherer7aced172000-08-15 01:13:23 +000098class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +000099 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000100
David Scherer7aced172000-08-15 01:13:23 +0000101 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000102 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000103 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000104 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000105 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000106 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
107
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000108 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
109 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000110 # whenever a file is changed, restore breakpoints
111 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000112 def filename_changed_hook(old_hook=self.io.filename_change_hook,
113 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000114 self.restore_file_breaks()
115 old_hook()
116 self.io.set_filename_change_hook(filename_changed_hook)
117
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000118 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
119 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000120
Chui Teya2adb0f2002-11-04 22:14:54 +0000121 def set_breakpoint(self, lineno):
122 text = self.text
123 filename = self.io.filename
124 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
125 try:
126 i = self.breakpoints.index(lineno)
127 except ValueError: # only add if missing, i.e. do once
128 self.breakpoints.append(lineno)
129 try: # update the subprocess debugger
130 debug = self.flist.pyshell.interp.debugger
131 debug.set_breakpoint_here(filename, lineno)
132 except: # but debugger may not be active right now....
133 pass
134
David Scherer7aced172000-08-15 01:13:23 +0000135 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000136 text = self.text
137 filename = self.io.filename
138 if not filename:
139 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000140 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000141 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000142 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000143
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000144 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000145 text = self.text
146 filename = self.io.filename
147 if not filename:
148 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000149 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000150 lineno = int(float(text.index("insert")))
151 try:
152 self.breakpoints.remove(lineno)
153 except:
154 pass
155 text.tag_remove("BREAK", "insert linestart",\
156 "insert lineend +1char")
157 try:
158 debug = self.flist.pyshell.interp.debugger
159 debug.clear_breakpoint_here(filename, lineno)
160 except:
161 pass
162
163 def clear_file_breaks(self):
164 if self.breakpoints:
165 text = self.text
166 filename = self.io.filename
167 if not filename:
168 text.bell()
169 return
170 self.breakpoints = []
171 text.tag_remove("BREAK", "1.0", END)
172 try:
173 debug = self.flist.pyshell.interp.debugger
174 debug.clear_file_breaks(filename)
175 except:
176 pass
177
Chui Teya2adb0f2002-11-04 22:14:54 +0000178 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000179 "Save breakpoints when file is saved"
180 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
181 # be run. The breaks are saved at that time. If we introduce
182 # a temporary file save feature the save breaks functionality
183 # needs to be re-verified, since the breaks at the time the
184 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000185 # permanent save of the file. Currently, a break introduced
186 # after a save will be effective, but not persistent.
187 # This is necessary to keep the saved breaks synched with the
188 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000189 #
190 # Breakpoints are set as tagged ranges in the text. Certain
191 # kinds of edits cause these ranges to be deleted: Inserting
192 # or deleting a line just before a breakpoint, and certain
193 # deletions prior to a breakpoint. These issues need to be
194 # investigated and understood. It's not clear if they are
195 # Tk issues or IDLE issues, or whether they can actually
196 # be fixed. Since a modified file has to be saved before it is
197 # run, and since self.breakpoints (from which the subprocess
198 # debugger is loaded) is updated during the save, the visible
199 # breaks stay synched with the subprocess even if one of these
200 # unexpected breakpoint deletions occurs.
201 breaks = self.breakpoints
202 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000203 try:
Victor Stinner85c67722011-09-02 00:57:04 +0200204 with open(self.breakpointPath, "r") as fp:
205 lines = fp.readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000206 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000207 lines = []
Victor Stinner85c67722011-09-02 00:57:04 +0200208 with open(self.breakpointPath, "w") as new_file:
209 for line in lines:
210 if not line.startswith(filename + '='):
211 new_file.write(line)
212 self.update_breakpoints()
213 breaks = self.breakpoints
214 if breaks:
215 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000216
217 def restore_file_breaks(self):
218 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000219 filename = self.io.filename
220 if filename is None:
221 return
Chui Tey69371d62002-11-04 23:39:45 +0000222 if os.path.isfile(self.breakpointPath):
Victor Stinner85c67722011-09-02 00:57:04 +0200223 with open(self.breakpointPath, "r") as fp:
224 lines = fp.readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000225 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000226 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000227 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000228 for breakpoint_linenumber in breakpoint_linenumbers:
229 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000230
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000231 def update_breakpoints(self):
232 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000233 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000234 ranges = text.tag_ranges("BREAK")
235 linenumber_list = self.ranges_to_linenumbers(ranges)
236 self.breakpoints = linenumber_list
237
238 def ranges_to_linenumbers(self, ranges):
239 lines = []
240 for index in range(0, len(ranges), 2):
241 lineno = int(float(ranges[index]))
242 end = int(float(ranges[index+1]))
243 while lineno < end:
244 lines.append(lineno)
245 lineno += 1
246 return lines
247
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000248# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000249# def saved_change_hook(self):
250# "Extend base method - clear breaks if module is modified"
251# if not self.get_saved():
252# self.clear_file_breaks()
253# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000254
255 def _close(self):
256 "Extend base method - clear breaks when module is closed"
257 self.clear_file_breaks()
258 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000259
David Scherer7aced172000-08-15 01:13:23 +0000260
261class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000262 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000263
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000264 # override FileList's class variable, instances return PyShellEditorWindow
265 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000266 EditorWindow = PyShellEditorWindow
267
268 pyshell = None
269
270 def open_shell(self, event=None):
271 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000272 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000273 else:
274 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000275 if self.pyshell:
276 if not self.pyshell.begin():
277 return None
David Scherer7aced172000-08-15 01:13:23 +0000278 return self.pyshell
279
280
281class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000282 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000283
Steven M. Gavab77d3432002-03-02 07:16:21 +0000284 def __init__(self):
285 ColorDelegator.__init__(self)
286 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000287
288 def recolorize_main(self):
289 self.tag_remove("TODO", "1.0", "iomark")
290 self.tag_add("SYNC", "1.0", "iomark")
291 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000292
Steven M. Gavab77d3432002-03-02 07:16:21 +0000293 def LoadTagDefs(self):
294 ColorDelegator.LoadTagDefs(self)
295 theme = idleConf.GetOption('main','Theme','name')
296 self.tagdefs.update({
297 "stdin": {'background':None,'foreground':None},
298 "stdout": idleConf.GetHighlight(theme, "stdout"),
299 "stderr": idleConf.GetHighlight(theme, "stderr"),
300 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000301 })
David Scherer7aced172000-08-15 01:13:23 +0000302
David Scherer7aced172000-08-15 01:13:23 +0000303class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000304 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000305
306 def insert(self, index, chars, tags=None):
307 try:
308 if self.delegate.compare(index, "<", "iomark"):
309 self.delegate.bell()
310 return
311 except TclError:
312 pass
313 UndoDelegator.insert(self, index, chars, tags)
314
315 def delete(self, index1, index2=None):
316 try:
317 if self.delegate.compare(index1, "<", "iomark"):
318 self.delegate.bell()
319 return
320 except TclError:
321 pass
322 UndoDelegator.delete(self, index1, index2)
323
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000324
325class MyRPCClient(rpc.RPCClient):
326
327 def handle_EOF(self):
328 "Override the base class - just re-raise EOFError"
329 raise EOFError
330
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000331
David Scherer7aced172000-08-15 01:13:23 +0000332class ModifiedInterpreter(InteractiveInterpreter):
333
334 def __init__(self, tkconsole):
335 self.tkconsole = tkconsole
336 locals = sys.modules['__main__'].__dict__
337 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000338 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000339 self.restarting = False
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000340 self.subprocess_arglist = None
341 self.port = PORT
David Scherer7aced172000-08-15 01:13:23 +0000342
Chui Tey5d2af632002-05-26 13:36:41 +0000343 rpcclt = None
Ned Deilye5cad232011-08-02 18:47:13 -0700344 rpcsubproc = None
Chui Tey5d2af632002-05-26 13:36:41 +0000345
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000346 def spawn_subprocess(self):
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000347 if self.subprocess_arglist is None:
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000348 self.subprocess_arglist = self.build_subprocess_arglist()
Ned Deilye5cad232011-08-02 18:47:13 -0700349 self.rpcsubproc = subprocess.Popen(self.subprocess_arglist)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000350
Tony Lowndsf53dec22002-12-20 04:24:43 +0000351 def build_subprocess_arglist(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000352 assert (self.port!=0), (
353 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000354 w = ['-W' + s for s in sys.warnoptions]
355 # Maybe IDLE is installed and is being accessed via sys.path,
356 # or maybe it's not installed and the idle.py script is being
357 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000358 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
359 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000360 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000361 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000362 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000363 command = "__import__('run').main(%r)" % (del_exitf,)
Ned Deilye5cad232011-08-02 18:47:13 -0700364 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000365
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000366 def start_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000367 addr = (HOST, self.port)
368 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000369 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000370 time.sleep(i)
371 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000372 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000373 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000374 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000375 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000376 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000377 self.display_port_binding_error()
378 return None
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000379 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
380 self.port = self.rpcclt.listening_sock.getsockname()[1]
381 # if PORT was not 0, probably working with a remote execution server
382 if PORT != 0:
383 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
384 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
385 # on Windows since the implementation allows two active sockets on
386 # the same address!
387 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
388 socket.SO_REUSEADDR, 1)
389 self.spawn_subprocess()
390 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000391 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000392 self.rpcclt.listening_sock.settimeout(10)
393 try:
394 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000395 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000396 self.display_no_subprocess_error()
397 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000398 self.rpcclt.register("stdin", self.tkconsole)
399 self.rpcclt.register("stdout", self.tkconsole.stdout)
400 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000401 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000402 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000403 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000404 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000405 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000406 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000407
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000408 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000409 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000410 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000411 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000412 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000413 debug = self.getdebugger()
414 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000415 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000416 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000417 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
418 except:
419 pass
420 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000421 self.rpcclt.close()
Ned Deilye5cad232011-08-02 18:47:13 -0700422 self.terminate_subprocess()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000423 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000424 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000425 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000426 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000427 try:
428 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000429 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000430 self.display_no_subprocess_error()
431 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000432 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000433 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000434 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000435 if was_executing:
436 console.write('\n')
437 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000438 halfbar = ((int(console.width) - 16) // 2) * '='
439 console.write(halfbar + ' RESTART ' + halfbar)
440 console.text.mark_set("restart", "end-1c")
441 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000442 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000444 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000445 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000446 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000447 # reload remote debugger breakpoints for all PyShellEditWindows
448 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000449 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000450 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000451
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000453 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000454
455 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000456 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000457
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000458 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000459 try:
460 self.rpcclt.close()
461 except AttributeError: # no socket
462 pass
Ned Deilye5cad232011-08-02 18:47:13 -0700463 self.terminate_subprocess()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000464 self.tkconsole.executing = False
465 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000466
Ned Deilye5cad232011-08-02 18:47:13 -0700467 def terminate_subprocess(self):
468 "Make sure subprocess is terminated"
469 try:
470 self.rpcsubproc.kill()
471 except OSError:
472 # process already terminated
473 return
474 else:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000475 try:
Ned Deilye5cad232011-08-02 18:47:13 -0700476 self.rpcsubproc.wait()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000477 except OSError:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000478 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000479
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000480 def transfer_path(self):
481 self.runcommand("""if 1:
482 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000483 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000484 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000485 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000486
Chui Tey5d2af632002-05-26 13:36:41 +0000487 active_seq = None
488
489 def poll_subprocess(self):
490 clt = self.rpcclt
491 if clt is None:
492 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000493 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000494 response = clt.pollresponse(self.active_seq, wait=0.05)
495 except (EOFError, IOError, KeyboardInterrupt):
496 # lost connection or subprocess terminated itself, restart
497 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000498 if self.tkconsole.closing:
499 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000500 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000501 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000502 if response:
503 self.tkconsole.resetoutput()
504 self.active_seq = None
505 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000506 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000507 if how == "OK":
508 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000509 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000510 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000511 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
512 self.remote_stack_viewer()
513 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000514 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000515 print(errmsg, what, file=sys.__stderr__)
516 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000517 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000518 try:
519 self.tkconsole.endexecuting()
520 except AttributeError: # shell may have closed
521 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000522 # Reschedule myself
523 if not self.tkconsole.closing:
524 self.tkconsole.text.after(self.tkconsole.pollinterval,
525 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000526
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000527 debugger = None
528
529 def setdebugger(self, debugger):
530 self.debugger = debugger
531
532 def getdebugger(self):
533 return self.debugger
534
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000535 def open_remote_stack_viewer(self):
536 """Initiate the remote stack viewer from a separate thread.
537
538 This method is called from the subprocess, and by returning from this
539 method we allow the subprocess to unblock. After a bit the shell
540 requests the subprocess to open the remote stack viewer which returns a
Ezio Melotti60861182010-07-23 16:48:22 +0000541 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000542 the RPC mechanism.
543
544 """
545 self.tkconsole.text.after(300, self.remote_stack_viewer)
546 return
547
Chui Tey5d2af632002-05-26 13:36:41 +0000548 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000549 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000550 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000551 if oid is None:
552 self.tkconsole.root.bell()
553 return
554 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000555 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000556 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000557 theme = idleConf.GetOption('main','Theme','name')
558 background = idleConf.GetHighlight(theme, 'normal')['background']
559 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000560 sc.frame.pack(expand=1, fill="both")
561 node = TreeNode(sc.canvas, None, item)
562 node.expand()
563 # XXX Should GC the remote tree when closing the window
564
David Scherer7aced172000-08-15 01:13:23 +0000565 gid = 0
566
567 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000568 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000569 filename = self.stuffsource(source)
570 self.execfile(filename, source)
571
572 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000573 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000574 if source is None:
Victor Stinner85c67722011-09-02 00:57:04 +0200575 with open(filename, "r") as fp:
576 source = fp.read()
David Scherer7aced172000-08-15 01:13:23 +0000577 try:
578 code = compile(source, filename, "exec")
579 except (OverflowError, SyntaxError):
580 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000581 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000582 print('*** Error in script or command!\n', file=tkerr)
583 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000584 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000585 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000586 else:
587 self.runcode(code)
588
589 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000590 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000591 filename = self.stuffsource(source)
592 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000593 self.save_warnings_filters = warnings.filters[:]
594 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000595 # at the moment, InteractiveInterpreter expects str
596 assert isinstance(source, str)
597 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000598 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000599 # try:
600 # source = source.encode(IOBinding.encoding)
601 # except UnicodeError:
602 # self.tkconsole.resetoutput()
603 # self.write("Unsupported characters in input\n")
604 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000605 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000606 # InteractiveInterpreter.runsource() calls its runcode() method,
607 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000608 return InteractiveInterpreter.runsource(self, source, filename)
609 finally:
610 if self.save_warnings_filters is not None:
611 warnings.filters[:] = self.save_warnings_filters
612 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000613
614 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000615 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000616 filename = "<pyshell#%d>" % self.gid
617 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000618 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000619 linecache.cache[filename] = len(source)+1, 0, lines, filename
620 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000621
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000622 def prepend_syspath(self, filename):
623 "Prepend sys.path with file's directory if not already included"
624 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000625 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000626 import sys as _sys
627 from os.path import dirname as _dirname
628 _dir = _dirname(_filename)
629 if not _dir in _sys.path:
630 _sys.path.insert(0, _dir)
631 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000632 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000633
David Scherer7aced172000-08-15 01:13:23 +0000634 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000635 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000636
637 Color the offending position instead of printing it and pointing at it
638 with a caret.
639
640 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000641 tkconsole = self.tkconsole
642 text = tkconsole.text
643 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000644 type, value, tb = sys.exc_info()
Guido van Rossum33d26892007-08-05 15:29:28 +0000645 msg = value.msg or "<no detail available>"
646 lineno = value.lineno or 1
647 offset = value.offset or 0
648 if offset == 0:
649 lineno += 1 #mark end of offending line
650 if lineno == 1:
651 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000652 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000653 pos = "iomark linestart + %d lines + %d chars" % \
654 (lineno-1, offset-1)
655 tkconsole.colorize_syntax_error(text, pos)
656 tkconsole.resetoutput()
657 self.write("SyntaxError: %s\n" % msg)
658 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000659
660 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000661 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000662 self.tkconsole.resetoutput()
663 self.checklinecache()
664 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000665 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
666 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000667
668 def checklinecache(self):
669 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000670 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000671 if key[:1] + key[-1:] != "<>":
672 del c[key]
673
Chui Tey5d2af632002-05-26 13:36:41 +0000674 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000675 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000676 # The code better not raise an exception!
677 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000678 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000679 return 0
680 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000681 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000682 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000683 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000684 return 1
685
David Scherer7aced172000-08-15 01:13:23 +0000686 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000687 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000688 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000689 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000690 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000691 if self.save_warnings_filters is not None:
692 warnings.filters[:] = self.save_warnings_filters
693 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000694 debugger = self.debugger
695 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000696 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000697 if not debugger and self.rpcclt is not None:
698 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
699 (code,), {})
700 elif debugger:
701 debugger.run(code, self.locals)
702 else:
703 exec(code, self.locals)
704 except SystemExit:
705 if not self.tkconsole.closing:
706 if tkMessageBox.askyesno(
707 "Exit?",
708 "Do you want to exit altogether?",
709 default="yes",
710 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000711 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000712 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000713 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000714 else:
715 raise
716 except:
717 if use_subprocess:
718 print("IDLE internal error in runcode()",
719 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000720 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000721 self.tkconsole.endexecuting()
722 else:
723 if self.tkconsole.canceled:
724 self.tkconsole.canceled = False
725 print("KeyboardInterrupt", file=self.tkconsole.stderr)
726 else:
727 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000728 finally:
729 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000730 try:
731 self.tkconsole.endexecuting()
732 except AttributeError: # shell may have closed
733 pass
David Scherer7aced172000-08-15 01:13:23 +0000734
735 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000736 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000737 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000738
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000739 def display_port_binding_error(self):
740 tkMessageBox.showerror(
741 "Port Binding Error",
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000742 "IDLE can't bind to a TCP/IP port, which is necessary to "
743 "communicate with its Python execution server. This might be "
744 "because no networking is installed on this computer. "
745 "Run IDLE with the -n command line switch to start without a "
746 "subprocess and refer to Help/IDLE Help 'Running without a "
747 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000748 master=self.tkconsole.text)
749
750 def display_no_subprocess_error(self):
751 tkMessageBox.showerror(
752 "Subprocess Startup Error",
753 "IDLE's subprocess didn't make connection. Either IDLE can't "
754 "start a subprocess or personal firewall software is blocking "
755 "the connection.",
756 master=self.tkconsole.text)
757
758 def display_executing_dialog(self):
759 tkMessageBox.showerror(
760 "Already executing",
761 "The Python Shell window is already executing a command; "
762 "please wait until it is finished.",
763 master=self.tkconsole.text)
764
765
David Scherer7aced172000-08-15 01:13:23 +0000766class PyShell(OutputWindow):
767
768 shell_title = "Python Shell"
769
770 # Override classes
771 ColorDelegator = ModifiedColorDelegator
772 UndoDelegator = ModifiedUndoDelegator
773
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000774 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000775 menu_specs = [
776 ("file", "_File"),
777 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000778 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000779 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000780 ("windows", "_Windows"),
781 ("help", "_Help"),
782 ]
David Scherer7aced172000-08-15 01:13:23 +0000783
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000784 if macosxSupport.runningAsOSXApp():
785 del menu_specs[-3]
786 menu_specs[-2] = ("windows", "_Window")
787
788
David Scherer7aced172000-08-15 01:13:23 +0000789 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000790 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000791
792 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000793 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000794 ms = self.menu_specs
795 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000796 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000797 self.interp = ModifiedInterpreter(self)
798 if flist is None:
799 root = Tk()
800 fixwordbreaks(root)
801 root.withdraw()
802 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000803 #
David Scherer7aced172000-08-15 01:13:23 +0000804 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000805 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000806## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
807 self.usetabs = True
808 # indentwidth must be 8 when using tabs. See note in EditorWindow:
809 self.indentwidth = 8
810 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000811 #
David Scherer7aced172000-08-15 01:13:23 +0000812 text = self.text
813 text.configure(wrap="char")
814 text.bind("<<newline-and-indent>>", self.enter_callback)
815 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
816 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000817 text.bind("<<end-of-file>>", self.eof_callback)
818 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000819 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000820 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8a78cad2007-12-13 03:38:16 +0000821 self.color = color = self.ColorDelegator()
822 self.per.insertfilter(color)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000823 if use_subprocess:
824 text.bind("<<view-restart>>", self.view_restart_mark)
825 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000826 #
David Scherer7aced172000-08-15 01:13:23 +0000827 self.save_stdout = sys.stdout
828 self.save_stderr = sys.stderr
829 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000830 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000831 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
832 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
833 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000834 if not use_subprocess:
835 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000836 sys.stderr = self.stderr
Chui Tey5d2af632002-05-26 13:36:41 +0000837 sys.stdin = self
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000838 try:
839 # page help() text to shell.
840 import pydoc # import must be done here to capture i/o rebinding.
841 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
842 pydoc.pager = pydoc.plainpager
843 except:
844 sys.stderr = sys.__stderr__
845 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000846 #
David Scherer7aced172000-08-15 01:13:23 +0000847 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000848 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000849 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000850
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000851 def get_standard_extension_names(self):
852 return idleConf.GetExtensions(shell_only=True)
853
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000854 reading = False
855 executing = False
856 canceled = False
857 endoffile = False
858 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000859
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000860 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000861 global warning_stream
862 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000863
864 def get_warning_stream(self):
865 return warning_stream
866
David Scherer7aced172000-08-15 01:13:23 +0000867 def toggle_debugger(self, event=None):
868 if self.executing:
869 tkMessageBox.showerror("Don't debug now",
870 "You can only toggle the debugger when idle",
871 master=self.text)
872 self.set_debugger_indicator()
873 return "break"
874 else:
875 db = self.interp.getdebugger()
876 if db:
877 self.close_debugger()
878 else:
879 self.open_debugger()
880
881 def set_debugger_indicator(self):
882 db = self.interp.getdebugger()
883 self.setvar("<<toggle-debugger>>", not not db)
884
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000885 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000886 pass # All we need is the variable
887
888 def close_debugger(self):
889 db = self.interp.getdebugger()
890 if db:
891 self.interp.setdebugger(None)
892 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000893 if self.interp.rpcclt:
894 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000895 self.resetoutput()
896 self.console.write("[DEBUG OFF]\n")
897 sys.ps1 = ">>> "
898 self.showprompt()
899 self.set_debugger_indicator()
900
901 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000902 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000903 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
904 self)
905 else:
906 dbg_gui = Debugger.Debugger(self)
907 self.interp.setdebugger(dbg_gui)
908 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000909 sys.ps1 = "[DEBUG ON]\n>>> "
910 self.showprompt()
911 self.set_debugger_indicator()
912
David Scherer7aced172000-08-15 01:13:23 +0000913 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000914 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000915 self.resetoutput()
916 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000917
918 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000919 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000920 self.executing = 0
921 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000922 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000923
924 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000925 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000926 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000927 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000928 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000929 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000930 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000931 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000932 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000933 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000934 if self.reading:
935 self.top.quit()
936 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000937 self.closing = True
938 # Wait for poll_subprocess() rescheduling to stop
939 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000940
941 def close2(self):
942 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000943
944 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000945 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000946 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000947 if use_subprocess:
948 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000949 # Restore std streams
950 sys.stdout = self.save_stdout
951 sys.stderr = self.save_stderr
952 sys.stdin = self.save_stdin
953 # Break cycles
954 self.interp = None
955 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000956 self.flist.pyshell = None
957 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000958 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000959
960 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000961 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000962 return True
David Scherer7aced172000-08-15 01:13:23 +0000963
964 def short_title(self):
965 return self.shell_title
966
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000967 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000968 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000969
David Scherer7aced172000-08-15 01:13:23 +0000970 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +0000971 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +0000972 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000973 if use_subprocess:
974 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000975 client = self.interp.start_subprocess()
976 if not client:
977 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000978 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000979 else:
980 nosub = "==== No Subprocess ===="
Raymond Hettingera2a8e8b2009-01-27 00:28:36 +0000981 self.write("Python %s on %s\n%s\n%s" %
982 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000983 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +0000984 import tkinter
985 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000986 return True
David Scherer7aced172000-08-15 01:13:23 +0000987
988 def readline(self):
989 save = self.reading
990 try:
991 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000992 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +0000993 finally:
994 self.reading = save
995 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000996 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
997 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +0000998 self.resetoutput()
999 if self.canceled:
1000 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001001 if not use_subprocess:
1002 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001003 if self.endoffile:
1004 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001005 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001006 return line
1007
1008 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001009 return True
David Scherer7aced172000-08-15 01:13:23 +00001010
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001011 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001012 try:
1013 if self.text.compare("sel.first", "!=", "sel.last"):
1014 return # Active selection -- always use default binding
1015 except:
1016 pass
1017 if not (self.executing or self.reading):
1018 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001019 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001020 self.showprompt()
1021 return "break"
1022 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001023 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001024 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001025 if self.interp.getdebugger():
1026 self.interp.restart_subprocess()
1027 else:
1028 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001029 if self.reading:
1030 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001031 return "break"
1032
1033 def eof_callback(self, event):
1034 if self.executing and not self.reading:
1035 return # Let the default binding (delete next char) take over
1036 if not (self.text.compare("iomark", "==", "insert") and
1037 self.text.compare("insert", "==", "end-1c")):
1038 return # Let the default binding (delete next char) take over
1039 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001040 self.resetoutput()
1041 self.close()
1042 else:
1043 self.canceled = 0
1044 self.endoffile = 1
1045 self.top.quit()
1046 return "break"
1047
David Scherer7aced172000-08-15 01:13:23 +00001048 def linefeed_callback(self, event):
1049 # Insert a linefeed without entering anything (still autoindented)
1050 if self.reading:
1051 self.text.insert("insert", "\n")
1052 self.text.see("insert")
1053 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001054 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001055 return "break"
1056
1057 def enter_callback(self, event):
1058 if self.executing and not self.reading:
1059 return # Let the default binding (insert '\n') take over
1060 # If some text is selected, recall the selection
1061 # (but only if this before the I/O mark)
1062 try:
1063 sel = self.text.get("sel.first", "sel.last")
1064 if sel:
1065 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001066 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001067 return "break"
1068 except:
1069 pass
1070 # If we're strictly before the line containing iomark, recall
1071 # the current line, less a leading prompt, less leading or
1072 # trailing whitespace
1073 if self.text.compare("insert", "<", "iomark linestart"):
1074 # Check if there's a relevant stdin range -- if so, use it
1075 prev = self.text.tag_prevrange("stdin", "insert")
1076 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001077 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001078 return "break"
1079 next = self.text.tag_nextrange("stdin", "insert")
1080 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001081 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001082 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001083 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001084 indices = self.text.tag_nextrange("console", "insert linestart")
1085 if indices and \
1086 self.text.compare(indices[0], "<=", "insert linestart"):
1087 self.recall(self.text.get(indices[1], "insert lineend"), event)
1088 else:
1089 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001090 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001091 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001092 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001093 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001094 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001095 # If we're in the current input and there's only whitespace
1096 # beyond the cursor, erase that whitespace first
1097 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001098 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001099 self.text.delete("insert", "end-1c")
1100 # If we're in the current input before its last line,
1101 # insert a newline right at the insert point
1102 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001103 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001104 return "break"
1105 # We're in the last line; append a newline and submit it
1106 self.text.mark_set("insert", "end-1c")
1107 if self.reading:
1108 self.text.insert("insert", "\n")
1109 self.text.see("insert")
1110 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001111 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001112 self.text.tag_add("stdin", "iomark", "end-1c")
1113 self.text.update_idletasks()
1114 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001115 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001116 else:
1117 self.runit()
1118 return "break"
1119
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001120 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001121 # remove leading and trailing empty or whitespace lines
1122 s = re.sub(r'^\s*\n', '' , s)
1123 s = re.sub(r'\n\s*$', '', s)
1124 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001125 self.text.undo_block_start()
1126 try:
1127 self.text.tag_remove("sel", "1.0", "end")
1128 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001129 prefix = self.text.get("insert linestart", "insert")
1130 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001131 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001132 prefix = self.text.get("insert linestart", "insert")
1133 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001134 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001135 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1136 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001137 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001138 if line.startswith(orig_base_indent):
1139 # replace orig base indentation with new indentation
1140 line = new_base_indent + line[len(orig_base_indent):]
1141 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001142 finally:
1143 self.text.see("insert")
1144 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001145
1146 def runit(self):
1147 line = self.text.get("iomark", "end-1c")
1148 # Strip off last newline and surrounding whitespace.
1149 # (To allow you to hit return twice to end a statement.)
1150 i = len(line)
1151 while i > 0 and line[i-1] in " \t":
1152 i = i-1
1153 if i > 0 and line[i-1] == "\n":
1154 i = i-1
1155 while i > 0 and line[i-1] in " \t":
1156 i = i-1
1157 line = line[:i]
1158 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001159
David Scherer7aced172000-08-15 01:13:23 +00001160 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001161 if self.interp.rpcclt:
1162 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001163 try:
1164 sys.last_traceback
1165 except:
1166 tkMessageBox.showerror("No stack trace",
1167 "There is no stack trace yet.\n"
1168 "(sys.last_traceback is not defined)",
1169 master=self.text)
1170 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001171 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001172 sv = StackBrowser(self.root, self.flist)
1173
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001174 def view_restart_mark(self, event=None):
1175 self.text.see("iomark")
1176 self.text.see("restart")
1177
1178 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001179 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001180
David Scherer7aced172000-08-15 01:13:23 +00001181 def showprompt(self):
1182 self.resetoutput()
1183 try:
1184 s = str(sys.ps1)
1185 except:
1186 s = ""
1187 self.console.write(s)
1188 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001189 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001190 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001191
1192 def resetoutput(self):
1193 source = self.text.get("iomark", "end-1c")
1194 if self.history:
1195 self.history.history_store(source)
1196 if self.text.get("end-2c") != "\n":
1197 self.text.insert("end-1c", "\n")
1198 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001199 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001200
1201 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001202 try:
1203 self.text.mark_gravity("iomark", "right")
1204 OutputWindow.write(self, s, tags, "iomark")
1205 self.text.mark_gravity("iomark", "left")
1206 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001207 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1208 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001209 if self.canceled:
1210 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001211 if not use_subprocess:
1212 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001213
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001214class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001215
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001216 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001217 self.shell = shell
1218 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001219 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001220
1221 def write(self, s):
1222 self.shell.write(s, self.tags)
1223
Kurt B. Kaiser66aaf742007-08-09 18:00:23 +00001224 def writelines(self, lines):
1225 for line in lines:
1226 self.write(line)
David Scherer7aced172000-08-15 01:13:23 +00001227
1228 def flush(self):
1229 pass
1230
1231 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001232 return True
David Scherer7aced172000-08-15 01:13:23 +00001233
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001234
David Scherer7aced172000-08-15 01:13:23 +00001235usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001236
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001237USAGE: idle [-deins] [-t title] [file]*
1238 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1239 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001240
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001241 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001242 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001243
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001244The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001245
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001246 -e open an edit window
1247 -i open a shell window
1248
1249The following options imply -i and will open a shell:
1250
1251 -c cmd run the command in a shell, or
1252 -r file run script from file
1253
1254 -d enable the debugger
1255 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1256 -t title set title of shell window
1257
1258A default edit window will be bypassed when -c, -r, or - are used.
1259
1260[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1261
1262Examples:
1263
1264idle
1265 Open an edit window or shell depending on IDLE's configuration.
1266
1267idle foo.py foobar.py
1268 Edit the files, also open a shell if configured to start with shell.
1269
1270idle -est "Baz" foo.py
1271 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1272 window with the title "Baz".
1273
Neal Norwitz752abd02008-05-13 04:55:24 +00001274idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001275 Open a shell window and run the command, passing "-c" in sys.argv[0]
1276 and "foo" in sys.argv[1].
1277
1278idle -d -s -r foo.py "Hello World"
1279 Open a shell window, run a startup script, enable the debugger, and
1280 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1281 sys.argv[1].
1282
Neal Norwitz752abd02008-05-13 04:55:24 +00001283echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001284 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1285 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001286"""
1287
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001288def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001289 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001290
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001291 use_subprocess = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001292 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001293 enable_edit = False
1294 debug = False
1295 cmd = None
1296 script = None
1297 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001298 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001299 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001300 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001301 sys.stderr.write("Error: %s\n" % str(msg))
1302 sys.stderr.write(usage_msg)
1303 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001304 for o, a in opts:
1305 if o == '-c':
1306 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001307 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001308 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001309 debug = True
1310 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001311 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001312 enable_edit = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001313 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001314 if o == '-h':
1315 sys.stdout.write(usage_msg)
1316 sys.exit()
1317 if o == '-i':
1318 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001319 if o == '-n':
1320 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001321 if o == '-r':
1322 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001323 if os.path.isfile(script):
1324 pass
1325 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001326 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001327 sys.exit()
1328 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001329 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001330 startup = True
1331 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001332 if o == '-t':
1333 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001334 enable_shell = True
1335 if args and args[0] == '-':
1336 cmd = sys.stdin.read()
1337 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001338 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001339 for i in range(len(sys.path)):
1340 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001341 if args and args[0] == '-':
1342 sys.argv = [''] + args[1:]
1343 elif cmd:
1344 sys.argv = ['-c'] + args
1345 elif script:
1346 sys.argv = [script] + args
1347 elif args:
1348 enable_edit = True
1349 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001350 for filename in args:
1351 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001352 for dir in pathx:
1353 dir = os.path.abspath(dir)
1354 if not dir in sys.path:
1355 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001356 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001357 dir = os.getcwd()
1358 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001359 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001360 # check the IDLE settings configuration (but command line overrides)
1361 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001362 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001363 enable_edit = enable_edit or edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001365 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001366
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001367 fixwordbreaks(root)
1368 root.withdraw()
1369 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001370 macosxSupport.setupApp(root, flist)
1371
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001372 if enable_edit:
1373 if not (cmd or script):
1374 for filename in args:
1375 flist.open(filename)
1376 if not args:
1377 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001378 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001379 shell = flist.open_shell()
1380 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001381 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001382
1383 if macosxSupport.runningAsOSXApp() and flist.dict:
1384 # On OSX: when the user has double-clicked on a file that causes
1385 # IDLE to be launched the shell window will open just in front of
1386 # the file she wants to see. Lower the interpreter window when
1387 # there are open files.
1388 shell.top.lower()
1389
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001390 shell = flist.pyshell
1391 # handle remaining options:
1392 if debug:
1393 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001394 if startup:
1395 filename = os.environ.get("IDLESTARTUP") or \
1396 os.environ.get("PYTHONSTARTUP")
1397 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001398 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001399 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001400 shell.interp.runcommand("""if 1:
1401 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001402 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001403 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001404 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001405 if cmd:
1406 shell.interp.execsource(cmd)
1407 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001408 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001409 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001410
Ned Deily4ce92b22011-01-15 04:37:12 +00001411 # Check for problematic OS X Tk versions and print a warning message
1412 # in the IDLE shell window; this is less intrusive than always opening
1413 # a separate window.
1414 tkversionwarning = macosxSupport.tkVersionWarning(root)
1415 if tkversionwarning:
1416 shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
1417
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001418 root.mainloop()
1419 root.destroy()
1420
David Scherer7aced172000-08-15 01:13:23 +00001421if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001422 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001423 main()