blob: dcce2eb8bac7bb26c4edbcd70278db73cd6166db [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:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000204 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000205 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000206 lines = []
207 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000208 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000210 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000211 self.update_breakpoints()
212 breaks = self.breakpoints
213 if breaks:
214 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000215 new_file.close()
216
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):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000223 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000224 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000226 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000227 for breakpoint_linenumber in breakpoint_linenumbers:
228 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000229
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000230 def update_breakpoints(self):
231 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000232 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000233 ranges = text.tag_ranges("BREAK")
234 linenumber_list = self.ranges_to_linenumbers(ranges)
235 self.breakpoints = linenumber_list
236
237 def ranges_to_linenumbers(self, ranges):
238 lines = []
239 for index in range(0, len(ranges), 2):
240 lineno = int(float(ranges[index]))
241 end = int(float(ranges[index+1]))
242 while lineno < end:
243 lines.append(lineno)
244 lineno += 1
245 return lines
246
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000247# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000248# def saved_change_hook(self):
249# "Extend base method - clear breaks if module is modified"
250# if not self.get_saved():
251# self.clear_file_breaks()
252# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000253
254 def _close(self):
255 "Extend base method - clear breaks when module is closed"
256 self.clear_file_breaks()
257 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
David Scherer7aced172000-08-15 01:13:23 +0000259
260class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000261 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000262
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000263 # override FileList's class variable, instances return PyShellEditorWindow
264 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000265 EditorWindow = PyShellEditorWindow
266
267 pyshell = None
268
269 def open_shell(self, event=None):
270 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000271 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000272 else:
273 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000274 if self.pyshell:
275 if not self.pyshell.begin():
276 return None
David Scherer7aced172000-08-15 01:13:23 +0000277 return self.pyshell
278
279
280class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000281 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000282
Steven M. Gavab77d3432002-03-02 07:16:21 +0000283 def __init__(self):
284 ColorDelegator.__init__(self)
285 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000286
287 def recolorize_main(self):
288 self.tag_remove("TODO", "1.0", "iomark")
289 self.tag_add("SYNC", "1.0", "iomark")
290 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000291
Steven M. Gavab77d3432002-03-02 07:16:21 +0000292 def LoadTagDefs(self):
293 ColorDelegator.LoadTagDefs(self)
294 theme = idleConf.GetOption('main','Theme','name')
295 self.tagdefs.update({
296 "stdin": {'background':None,'foreground':None},
297 "stdout": idleConf.GetHighlight(theme, "stdout"),
298 "stderr": idleConf.GetHighlight(theme, "stderr"),
299 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000300 })
David Scherer7aced172000-08-15 01:13:23 +0000301
David Scherer7aced172000-08-15 01:13:23 +0000302class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000303 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000304
305 def insert(self, index, chars, tags=None):
306 try:
307 if self.delegate.compare(index, "<", "iomark"):
308 self.delegate.bell()
309 return
310 except TclError:
311 pass
312 UndoDelegator.insert(self, index, chars, tags)
313
314 def delete(self, index1, index2=None):
315 try:
316 if self.delegate.compare(index1, "<", "iomark"):
317 self.delegate.bell()
318 return
319 except TclError:
320 pass
321 UndoDelegator.delete(self, index1, index2)
322
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000323
324class MyRPCClient(rpc.RPCClient):
325
326 def handle_EOF(self):
327 "Override the base class - just re-raise EOFError"
328 raise EOFError
329
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000330
David Scherer7aced172000-08-15 01:13:23 +0000331class ModifiedInterpreter(InteractiveInterpreter):
332
333 def __init__(self, tkconsole):
334 self.tkconsole = tkconsole
335 locals = sys.modules['__main__'].__dict__
336 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000337 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000338 self.restarting = False
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000339 self.subprocess_arglist = None
340 self.port = PORT
David Scherer7aced172000-08-15 01:13:23 +0000341
Chui Tey5d2af632002-05-26 13:36:41 +0000342 rpcclt = None
Ned Deilye5cad232011-08-02 18:47:13 -0700343 rpcsubproc = None
Chui Tey5d2af632002-05-26 13:36:41 +0000344
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000345 def spawn_subprocess(self):
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000346 if self.subprocess_arglist is None:
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000347 self.subprocess_arglist = self.build_subprocess_arglist()
Ned Deilye5cad232011-08-02 18:47:13 -0700348 self.rpcsubproc = subprocess.Popen(self.subprocess_arglist)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000349
Tony Lowndsf53dec22002-12-20 04:24:43 +0000350 def build_subprocess_arglist(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000351 assert (self.port!=0), (
352 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000353 w = ['-W' + s for s in sys.warnoptions]
354 # Maybe IDLE is installed and is being accessed via sys.path,
355 # or maybe it's not installed and the idle.py script is being
356 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000357 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
358 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000359 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000360 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000361 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000362 command = "__import__('run').main(%r)" % (del_exitf,)
Ned Deilye5cad232011-08-02 18:47:13 -0700363 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000364
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000365 def start_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000366 addr = (HOST, self.port)
367 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000368 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000369 time.sleep(i)
370 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000371 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000372 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000373 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000374 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000375 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000376 self.display_port_binding_error()
377 return None
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000378 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
379 self.port = self.rpcclt.listening_sock.getsockname()[1]
380 # if PORT was not 0, probably working with a remote execution server
381 if PORT != 0:
382 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
383 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
384 # on Windows since the implementation allows two active sockets on
385 # the same address!
386 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
387 socket.SO_REUSEADDR, 1)
388 self.spawn_subprocess()
389 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000390 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000391 self.rpcclt.listening_sock.settimeout(10)
392 try:
393 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000394 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000395 self.display_no_subprocess_error()
396 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000397 self.rpcclt.register("stdin", self.tkconsole)
398 self.rpcclt.register("stdout", self.tkconsole.stdout)
399 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000400 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000401 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000402 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000403 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000404 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000405 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000406
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000407 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000408 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000409 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000410 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000411 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000412 debug = self.getdebugger()
413 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000414 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000415 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000416 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
417 except:
418 pass
419 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000420 self.rpcclt.close()
Ned Deilye5cad232011-08-02 18:47:13 -0700421 self.terminate_subprocess()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000422 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000423 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000424 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000425 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000426 try:
427 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000428 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000429 self.display_no_subprocess_error()
430 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000431 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000432 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000433 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000434 if was_executing:
435 console.write('\n')
436 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000437 halfbar = ((int(console.width) - 16) // 2) * '='
438 console.write(halfbar + ' RESTART ' + halfbar)
439 console.text.mark_set("restart", "end-1c")
440 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000441 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000442 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000443 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000444 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000445 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000446 # reload remote debugger breakpoints for all PyShellEditWindows
447 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000448 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000449 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000450
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000452 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000453
454 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000455 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000456
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000457 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000458 try:
459 self.rpcclt.close()
460 except AttributeError: # no socket
461 pass
Ned Deilye5cad232011-08-02 18:47:13 -0700462 self.terminate_subprocess()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000463 self.tkconsole.executing = False
464 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000465
Ned Deilye5cad232011-08-02 18:47:13 -0700466 def terminate_subprocess(self):
467 "Make sure subprocess is terminated"
468 try:
469 self.rpcsubproc.kill()
470 except OSError:
471 # process already terminated
472 return
473 else:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000474 try:
Ned Deilye5cad232011-08-02 18:47:13 -0700475 self.rpcsubproc.wait()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000476 except OSError:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000477 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000478
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000479 def transfer_path(self):
480 self.runcommand("""if 1:
481 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000482 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000483 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000484 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000485
Chui Tey5d2af632002-05-26 13:36:41 +0000486 active_seq = None
487
488 def poll_subprocess(self):
489 clt = self.rpcclt
490 if clt is None:
491 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000492 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000493 response = clt.pollresponse(self.active_seq, wait=0.05)
494 except (EOFError, IOError, KeyboardInterrupt):
495 # lost connection or subprocess terminated itself, restart
496 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000497 if self.tkconsole.closing:
498 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000499 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000500 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000501 if response:
502 self.tkconsole.resetoutput()
503 self.active_seq = None
504 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000505 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000506 if how == "OK":
507 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000508 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000509 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000510 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
511 self.remote_stack_viewer()
512 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000513 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000514 print(errmsg, what, file=sys.__stderr__)
515 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000516 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000517 try:
518 self.tkconsole.endexecuting()
519 except AttributeError: # shell may have closed
520 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000521 # Reschedule myself
522 if not self.tkconsole.closing:
523 self.tkconsole.text.after(self.tkconsole.pollinterval,
524 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000525
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000526 debugger = None
527
528 def setdebugger(self, debugger):
529 self.debugger = debugger
530
531 def getdebugger(self):
532 return self.debugger
533
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000534 def open_remote_stack_viewer(self):
535 """Initiate the remote stack viewer from a separate thread.
536
537 This method is called from the subprocess, and by returning from this
538 method we allow the subprocess to unblock. After a bit the shell
539 requests the subprocess to open the remote stack viewer which returns a
Ezio Melotti60861182010-07-23 16:48:22 +0000540 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000541 the RPC mechanism.
542
543 """
544 self.tkconsole.text.after(300, self.remote_stack_viewer)
545 return
546
Chui Tey5d2af632002-05-26 13:36:41 +0000547 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000548 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000549 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000550 if oid is None:
551 self.tkconsole.root.bell()
552 return
553 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000554 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000555 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000556 theme = idleConf.GetOption('main','Theme','name')
557 background = idleConf.GetHighlight(theme, 'normal')['background']
558 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000559 sc.frame.pack(expand=1, fill="both")
560 node = TreeNode(sc.canvas, None, item)
561 node.expand()
562 # XXX Should GC the remote tree when closing the window
563
David Scherer7aced172000-08-15 01:13:23 +0000564 gid = 0
565
566 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000567 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000568 filename = self.stuffsource(source)
569 self.execfile(filename, source)
570
571 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000572 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000573 if source is None:
574 source = open(filename, "r").read()
575 try:
576 code = compile(source, filename, "exec")
577 except (OverflowError, SyntaxError):
578 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000579 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000580 print('*** Error in script or command!\n', file=tkerr)
581 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000582 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000583 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000584 else:
585 self.runcode(code)
586
587 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000588 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000589 filename = self.stuffsource(source)
590 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000591 self.save_warnings_filters = warnings.filters[:]
592 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000593 # at the moment, InteractiveInterpreter expects str
594 assert isinstance(source, str)
595 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000596 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000597 # try:
598 # source = source.encode(IOBinding.encoding)
599 # except UnicodeError:
600 # self.tkconsole.resetoutput()
601 # self.write("Unsupported characters in input\n")
602 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000603 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000604 # InteractiveInterpreter.runsource() calls its runcode() method,
605 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000606 return InteractiveInterpreter.runsource(self, source, filename)
607 finally:
608 if self.save_warnings_filters is not None:
609 warnings.filters[:] = self.save_warnings_filters
610 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000611
612 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000613 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000614 filename = "<pyshell#%d>" % self.gid
615 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000616 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000617 linecache.cache[filename] = len(source)+1, 0, lines, filename
618 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000619
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000620 def prepend_syspath(self, filename):
621 "Prepend sys.path with file's directory if not already included"
622 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000623 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000624 import sys as _sys
625 from os.path import dirname as _dirname
626 _dir = _dirname(_filename)
627 if not _dir in _sys.path:
628 _sys.path.insert(0, _dir)
629 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000630 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000631
David Scherer7aced172000-08-15 01:13:23 +0000632 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000633 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000634
635 Color the offending position instead of printing it and pointing at it
636 with a caret.
637
638 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000639 tkconsole = self.tkconsole
640 text = tkconsole.text
641 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000642 type, value, tb = sys.exc_info()
Guido van Rossum33d26892007-08-05 15:29:28 +0000643 msg = value.msg or "<no detail available>"
644 lineno = value.lineno or 1
645 offset = value.offset or 0
646 if offset == 0:
647 lineno += 1 #mark end of offending line
648 if lineno == 1:
649 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000650 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000651 pos = "iomark linestart + %d lines + %d chars" % \
652 (lineno-1, offset-1)
653 tkconsole.colorize_syntax_error(text, pos)
654 tkconsole.resetoutput()
655 self.write("SyntaxError: %s\n" % msg)
656 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000657
658 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000659 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000660 self.tkconsole.resetoutput()
661 self.checklinecache()
662 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000663 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
664 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000665
666 def checklinecache(self):
667 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000668 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000669 if key[:1] + key[-1:] != "<>":
670 del c[key]
671
Chui Tey5d2af632002-05-26 13:36:41 +0000672 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000673 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000674 # The code better not raise an exception!
675 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000676 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000677 return 0
678 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000679 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000680 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000681 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000682 return 1
683
David Scherer7aced172000-08-15 01:13:23 +0000684 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000685 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000686 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000687 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000688 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000689 if self.save_warnings_filters is not None:
690 warnings.filters[:] = self.save_warnings_filters
691 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000692 debugger = self.debugger
693 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000694 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000695 if not debugger and self.rpcclt is not None:
696 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
697 (code,), {})
698 elif debugger:
699 debugger.run(code, self.locals)
700 else:
701 exec(code, self.locals)
702 except SystemExit:
703 if not self.tkconsole.closing:
704 if tkMessageBox.askyesno(
705 "Exit?",
706 "Do you want to exit altogether?",
707 default="yes",
708 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000709 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000710 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000711 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000712 else:
713 raise
714 except:
715 if use_subprocess:
716 print("IDLE internal error in runcode()",
717 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000718 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000719 self.tkconsole.endexecuting()
720 else:
721 if self.tkconsole.canceled:
722 self.tkconsole.canceled = False
723 print("KeyboardInterrupt", file=self.tkconsole.stderr)
724 else:
725 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000726 finally:
727 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000728 try:
729 self.tkconsole.endexecuting()
730 except AttributeError: # shell may have closed
731 pass
David Scherer7aced172000-08-15 01:13:23 +0000732
733 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000734 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000735 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000736
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000737 def display_port_binding_error(self):
738 tkMessageBox.showerror(
739 "Port Binding Error",
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000740 "IDLE can't bind to a TCP/IP port, which is necessary to "
741 "communicate with its Python execution server. This might be "
742 "because no networking is installed on this computer. "
743 "Run IDLE with the -n command line switch to start without a "
744 "subprocess and refer to Help/IDLE Help 'Running without a "
745 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000746 master=self.tkconsole.text)
747
748 def display_no_subprocess_error(self):
749 tkMessageBox.showerror(
750 "Subprocess Startup Error",
751 "IDLE's subprocess didn't make connection. Either IDLE can't "
752 "start a subprocess or personal firewall software is blocking "
753 "the connection.",
754 master=self.tkconsole.text)
755
756 def display_executing_dialog(self):
757 tkMessageBox.showerror(
758 "Already executing",
759 "The Python Shell window is already executing a command; "
760 "please wait until it is finished.",
761 master=self.tkconsole.text)
762
763
David Scherer7aced172000-08-15 01:13:23 +0000764class PyShell(OutputWindow):
765
766 shell_title = "Python Shell"
767
768 # Override classes
769 ColorDelegator = ModifiedColorDelegator
770 UndoDelegator = ModifiedUndoDelegator
771
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000772 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000773 menu_specs = [
774 ("file", "_File"),
775 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000776 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000777 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000778 ("windows", "_Windows"),
779 ("help", "_Help"),
780 ]
David Scherer7aced172000-08-15 01:13:23 +0000781
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000782 if macosxSupport.runningAsOSXApp():
783 del menu_specs[-3]
784 menu_specs[-2] = ("windows", "_Window")
785
786
David Scherer7aced172000-08-15 01:13:23 +0000787 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000788 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000789
790 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000791 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000792 ms = self.menu_specs
793 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000794 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000795 self.interp = ModifiedInterpreter(self)
796 if flist is None:
797 root = Tk()
798 fixwordbreaks(root)
799 root.withdraw()
800 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000801 #
David Scherer7aced172000-08-15 01:13:23 +0000802 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000803 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000804## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
805 self.usetabs = True
806 # indentwidth must be 8 when using tabs. See note in EditorWindow:
807 self.indentwidth = 8
808 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000809 #
David Scherer7aced172000-08-15 01:13:23 +0000810 text = self.text
811 text.configure(wrap="char")
812 text.bind("<<newline-and-indent>>", self.enter_callback)
813 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
814 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000815 text.bind("<<end-of-file>>", self.eof_callback)
816 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000817 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000818 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8a78cad2007-12-13 03:38:16 +0000819 self.color = color = self.ColorDelegator()
820 self.per.insertfilter(color)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000821 if use_subprocess:
822 text.bind("<<view-restart>>", self.view_restart_mark)
823 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000824 #
David Scherer7aced172000-08-15 01:13:23 +0000825 self.save_stdout = sys.stdout
826 self.save_stderr = sys.stderr
827 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000828 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000829 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
830 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
831 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000832 if not use_subprocess:
833 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000834 sys.stderr = self.stderr
Chui Tey5d2af632002-05-26 13:36:41 +0000835 sys.stdin = self
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000836 try:
837 # page help() text to shell.
838 import pydoc # import must be done here to capture i/o rebinding.
839 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
840 pydoc.pager = pydoc.plainpager
841 except:
842 sys.stderr = sys.__stderr__
843 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000844 #
David Scherer7aced172000-08-15 01:13:23 +0000845 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000846 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000847 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000848
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000849 def get_standard_extension_names(self):
850 return idleConf.GetExtensions(shell_only=True)
851
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000852 reading = False
853 executing = False
854 canceled = False
855 endoffile = False
856 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000857
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000858 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000859 global warning_stream
860 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000861
862 def get_warning_stream(self):
863 return warning_stream
864
David Scherer7aced172000-08-15 01:13:23 +0000865 def toggle_debugger(self, event=None):
866 if self.executing:
867 tkMessageBox.showerror("Don't debug now",
868 "You can only toggle the debugger when idle",
869 master=self.text)
870 self.set_debugger_indicator()
871 return "break"
872 else:
873 db = self.interp.getdebugger()
874 if db:
875 self.close_debugger()
876 else:
877 self.open_debugger()
878
879 def set_debugger_indicator(self):
880 db = self.interp.getdebugger()
881 self.setvar("<<toggle-debugger>>", not not db)
882
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000883 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000884 pass # All we need is the variable
885
886 def close_debugger(self):
887 db = self.interp.getdebugger()
888 if db:
889 self.interp.setdebugger(None)
890 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000891 if self.interp.rpcclt:
892 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000893 self.resetoutput()
894 self.console.write("[DEBUG OFF]\n")
895 sys.ps1 = ">>> "
896 self.showprompt()
897 self.set_debugger_indicator()
898
899 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000900 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000901 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
902 self)
903 else:
904 dbg_gui = Debugger.Debugger(self)
905 self.interp.setdebugger(dbg_gui)
906 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000907 sys.ps1 = "[DEBUG ON]\n>>> "
908 self.showprompt()
909 self.set_debugger_indicator()
910
David Scherer7aced172000-08-15 01:13:23 +0000911 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000912 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000913 self.resetoutput()
914 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000915
916 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000917 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000918 self.executing = 0
919 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000920 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000921
922 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000923 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000924 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000925 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000926 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000927 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000928 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000929 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000930 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000931 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000932 if self.reading:
933 self.top.quit()
934 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000935 self.closing = True
936 # Wait for poll_subprocess() rescheduling to stop
937 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000938
939 def close2(self):
940 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000941
942 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000943 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000944 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000945 if use_subprocess:
946 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000947 # Restore std streams
948 sys.stdout = self.save_stdout
949 sys.stderr = self.save_stderr
950 sys.stdin = self.save_stdin
951 # Break cycles
952 self.interp = None
953 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000954 self.flist.pyshell = None
955 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000956 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000957
958 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000959 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000960 return True
David Scherer7aced172000-08-15 01:13:23 +0000961
962 def short_title(self):
963 return self.shell_title
964
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000965 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000966 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000967
David Scherer7aced172000-08-15 01:13:23 +0000968 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +0000969 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +0000970 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000971 if use_subprocess:
972 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000973 client = self.interp.start_subprocess()
974 if not client:
975 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000976 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000977 else:
978 nosub = "==== No Subprocess ===="
Raymond Hettingera2a8e8b2009-01-27 00:28:36 +0000979 self.write("Python %s on %s\n%s\n%s" %
980 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000981 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +0000982 import tkinter
983 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000984 return True
David Scherer7aced172000-08-15 01:13:23 +0000985
986 def readline(self):
987 save = self.reading
988 try:
989 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000990 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +0000991 finally:
992 self.reading = save
993 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000994 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
995 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +0000996 self.resetoutput()
997 if self.canceled:
998 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000999 if not use_subprocess:
1000 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001001 if self.endoffile:
1002 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001003 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001004 return line
1005
1006 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001007 return True
David Scherer7aced172000-08-15 01:13:23 +00001008
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001009 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001010 try:
1011 if self.text.compare("sel.first", "!=", "sel.last"):
1012 return # Active selection -- always use default binding
1013 except:
1014 pass
1015 if not (self.executing or self.reading):
1016 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001017 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001018 self.showprompt()
1019 return "break"
1020 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001021 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001022 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001023 if self.interp.getdebugger():
1024 self.interp.restart_subprocess()
1025 else:
1026 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001027 if self.reading:
1028 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001029 return "break"
1030
1031 def eof_callback(self, event):
1032 if self.executing and not self.reading:
1033 return # Let the default binding (delete next char) take over
1034 if not (self.text.compare("iomark", "==", "insert") and
1035 self.text.compare("insert", "==", "end-1c")):
1036 return # Let the default binding (delete next char) take over
1037 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001038 self.resetoutput()
1039 self.close()
1040 else:
1041 self.canceled = 0
1042 self.endoffile = 1
1043 self.top.quit()
1044 return "break"
1045
David Scherer7aced172000-08-15 01:13:23 +00001046 def linefeed_callback(self, event):
1047 # Insert a linefeed without entering anything (still autoindented)
1048 if self.reading:
1049 self.text.insert("insert", "\n")
1050 self.text.see("insert")
1051 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001052 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001053 return "break"
1054
1055 def enter_callback(self, event):
1056 if self.executing and not self.reading:
1057 return # Let the default binding (insert '\n') take over
1058 # If some text is selected, recall the selection
1059 # (but only if this before the I/O mark)
1060 try:
1061 sel = self.text.get("sel.first", "sel.last")
1062 if sel:
1063 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001064 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001065 return "break"
1066 except:
1067 pass
1068 # If we're strictly before the line containing iomark, recall
1069 # the current line, less a leading prompt, less leading or
1070 # trailing whitespace
1071 if self.text.compare("insert", "<", "iomark linestart"):
1072 # Check if there's a relevant stdin range -- if so, use it
1073 prev = self.text.tag_prevrange("stdin", "insert")
1074 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001075 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001076 return "break"
1077 next = self.text.tag_nextrange("stdin", "insert")
1078 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001079 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001080 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001081 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001082 indices = self.text.tag_nextrange("console", "insert linestart")
1083 if indices and \
1084 self.text.compare(indices[0], "<=", "insert linestart"):
1085 self.recall(self.text.get(indices[1], "insert lineend"), event)
1086 else:
1087 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001088 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001089 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001090 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001091 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001092 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001093 # If we're in the current input and there's only whitespace
1094 # beyond the cursor, erase that whitespace first
1095 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001096 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001097 self.text.delete("insert", "end-1c")
1098 # If we're in the current input before its last line,
1099 # insert a newline right at the insert point
1100 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001101 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001102 return "break"
1103 # We're in the last line; append a newline and submit it
1104 self.text.mark_set("insert", "end-1c")
1105 if self.reading:
1106 self.text.insert("insert", "\n")
1107 self.text.see("insert")
1108 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001109 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001110 self.text.tag_add("stdin", "iomark", "end-1c")
1111 self.text.update_idletasks()
1112 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001113 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001114 else:
1115 self.runit()
1116 return "break"
1117
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001118 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001119 # remove leading and trailing empty or whitespace lines
1120 s = re.sub(r'^\s*\n', '' , s)
1121 s = re.sub(r'\n\s*$', '', s)
1122 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001123 self.text.undo_block_start()
1124 try:
1125 self.text.tag_remove("sel", "1.0", "end")
1126 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001127 prefix = self.text.get("insert linestart", "insert")
1128 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001129 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001130 prefix = self.text.get("insert linestart", "insert")
1131 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001132 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001133 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1134 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001135 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001136 if line.startswith(orig_base_indent):
1137 # replace orig base indentation with new indentation
1138 line = new_base_indent + line[len(orig_base_indent):]
1139 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001140 finally:
1141 self.text.see("insert")
1142 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001143
1144 def runit(self):
1145 line = self.text.get("iomark", "end-1c")
1146 # Strip off last newline and surrounding whitespace.
1147 # (To allow you to hit return twice to end a statement.)
1148 i = len(line)
1149 while i > 0 and line[i-1] in " \t":
1150 i = i-1
1151 if i > 0 and line[i-1] == "\n":
1152 i = i-1
1153 while i > 0 and line[i-1] in " \t":
1154 i = i-1
1155 line = line[:i]
1156 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001157
David Scherer7aced172000-08-15 01:13:23 +00001158 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001159 if self.interp.rpcclt:
1160 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001161 try:
1162 sys.last_traceback
1163 except:
1164 tkMessageBox.showerror("No stack trace",
1165 "There is no stack trace yet.\n"
1166 "(sys.last_traceback is not defined)",
1167 master=self.text)
1168 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001169 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001170 sv = StackBrowser(self.root, self.flist)
1171
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001172 def view_restart_mark(self, event=None):
1173 self.text.see("iomark")
1174 self.text.see("restart")
1175
1176 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001177 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001178
David Scherer7aced172000-08-15 01:13:23 +00001179 def showprompt(self):
1180 self.resetoutput()
1181 try:
1182 s = str(sys.ps1)
1183 except:
1184 s = ""
1185 self.console.write(s)
1186 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001187 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001188 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001189
1190 def resetoutput(self):
1191 source = self.text.get("iomark", "end-1c")
1192 if self.history:
1193 self.history.history_store(source)
1194 if self.text.get("end-2c") != "\n":
1195 self.text.insert("end-1c", "\n")
1196 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001197 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001198
1199 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001200 try:
1201 self.text.mark_gravity("iomark", "right")
1202 OutputWindow.write(self, s, tags, "iomark")
1203 self.text.mark_gravity("iomark", "left")
1204 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001205 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1206 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001207 if self.canceled:
1208 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001209 if not use_subprocess:
1210 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001211
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001212class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001213
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001214 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001215 self.shell = shell
1216 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001217 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001218
1219 def write(self, s):
1220 self.shell.write(s, self.tags)
1221
Kurt B. Kaiser66aaf742007-08-09 18:00:23 +00001222 def writelines(self, lines):
1223 for line in lines:
1224 self.write(line)
David Scherer7aced172000-08-15 01:13:23 +00001225
1226 def flush(self):
1227 pass
1228
1229 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001230 return True
David Scherer7aced172000-08-15 01:13:23 +00001231
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001232
David Scherer7aced172000-08-15 01:13:23 +00001233usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001234
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001235USAGE: idle [-deins] [-t title] [file]*
1236 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1237 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001238
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001239 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001240 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001241
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001242The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001243
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001244 -e open an edit window
1245 -i open a shell window
1246
1247The following options imply -i and will open a shell:
1248
1249 -c cmd run the command in a shell, or
1250 -r file run script from file
1251
1252 -d enable the debugger
1253 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1254 -t title set title of shell window
1255
1256A default edit window will be bypassed when -c, -r, or - are used.
1257
1258[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1259
1260Examples:
1261
1262idle
1263 Open an edit window or shell depending on IDLE's configuration.
1264
1265idle foo.py foobar.py
1266 Edit the files, also open a shell if configured to start with shell.
1267
1268idle -est "Baz" foo.py
1269 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1270 window with the title "Baz".
1271
Neal Norwitz752abd02008-05-13 04:55:24 +00001272idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001273 Open a shell window and run the command, passing "-c" in sys.argv[0]
1274 and "foo" in sys.argv[1].
1275
1276idle -d -s -r foo.py "Hello World"
1277 Open a shell window, run a startup script, enable the debugger, and
1278 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1279 sys.argv[1].
1280
Neal Norwitz752abd02008-05-13 04:55:24 +00001281echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001282 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1283 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001284"""
1285
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001286def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001287 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001288
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001289 use_subprocess = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001290 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001291 enable_edit = False
1292 debug = False
1293 cmd = None
1294 script = None
1295 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001296 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001297 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001298 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001299 sys.stderr.write("Error: %s\n" % str(msg))
1300 sys.stderr.write(usage_msg)
1301 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001302 for o, a in opts:
1303 if o == '-c':
1304 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001305 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001306 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001307 debug = True
1308 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001309 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001310 enable_edit = True
Kurt B. Kaisere866c812009-04-04 21:07:39 +00001311 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001312 if o == '-h':
1313 sys.stdout.write(usage_msg)
1314 sys.exit()
1315 if o == '-i':
1316 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001317 if o == '-n':
1318 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001319 if o == '-r':
1320 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001321 if os.path.isfile(script):
1322 pass
1323 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001324 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001325 sys.exit()
1326 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001327 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001328 startup = True
1329 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001330 if o == '-t':
1331 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001332 enable_shell = True
1333 if args and args[0] == '-':
1334 cmd = sys.stdin.read()
1335 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001336 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001337 for i in range(len(sys.path)):
1338 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001339 if args and args[0] == '-':
1340 sys.argv = [''] + args[1:]
1341 elif cmd:
1342 sys.argv = ['-c'] + args
1343 elif script:
1344 sys.argv = [script] + args
1345 elif args:
1346 enable_edit = True
1347 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001348 for filename in args:
1349 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001350 for dir in pathx:
1351 dir = os.path.abspath(dir)
1352 if not dir in sys.path:
1353 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001354 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001355 dir = os.getcwd()
1356 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001357 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001358 # check the IDLE settings configuration (but command line overrides)
1359 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001360 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001361 enable_edit = enable_edit or edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001362 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001363 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001364
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001365 fixwordbreaks(root)
1366 root.withdraw()
1367 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001368 macosxSupport.setupApp(root, flist)
1369
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001370 if enable_edit:
1371 if not (cmd or script):
1372 for filename in args:
1373 flist.open(filename)
1374 if not args:
1375 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001376 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001377 shell = flist.open_shell()
1378 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001379 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001380
1381 if macosxSupport.runningAsOSXApp() and flist.dict:
1382 # On OSX: when the user has double-clicked on a file that causes
1383 # IDLE to be launched the shell window will open just in front of
1384 # the file she wants to see. Lower the interpreter window when
1385 # there are open files.
1386 shell.top.lower()
1387
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001388 shell = flist.pyshell
1389 # handle remaining options:
1390 if debug:
1391 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001392 if startup:
1393 filename = os.environ.get("IDLESTARTUP") or \
1394 os.environ.get("PYTHONSTARTUP")
1395 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001396 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001397 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001398 shell.interp.runcommand("""if 1:
1399 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001400 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001401 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001402 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001403 if cmd:
1404 shell.interp.execsource(cmd)
1405 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001406 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001407 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001408
Ned Deily4ce92b22011-01-15 04:37:12 +00001409 # Check for problematic OS X Tk versions and print a warning message
1410 # in the IDLE shell window; this is less intrusive than always opening
1411 # a separate window.
1412 tkversionwarning = macosxSupport.tkVersionWarning(root)
1413 if tkversionwarning:
1414 shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
1415
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001416 root.mainloop()
1417 root.destroy()
1418
David Scherer7aced172000-08-15 01:13:23 +00001419if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001420 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001421 main()