blob: 567994e7b15c15cf568bbe068ab3c1982ec49108 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
2
David Scherer7aced172000-08-15 01:13:23 +00003import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00004import os.path
David Scherer7aced172000-08-15 01:13:23 +00005import sys
6import string
7import getopt
8import re
Chui Tey5d2af632002-05-26 13:36:41 +00009import socket
10import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000011import threading
Chui Tey5d2af632002-05-26 13:36:41 +000012import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000013import types
David Scherer7aced172000-08-15 01:13:23 +000014
15import linecache
16from code import InteractiveInterpreter
17
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000018try:
19 from Tkinter import *
20except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000021 print("** IDLE can't import Tkinter. " \
22 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000023 sys.exit(1)
David Scherer7aced172000-08-15 01:13:23 +000024import tkMessageBox
25
Guido van Rossum36e0a922007-07-20 04:05:57 +000026from .EditorWindow import EditorWindow, fixwordbreaks
27from .FileList import FileList
28from .ColorDelegator import ColorDelegator
29from .UndoDelegator import UndoDelegator
30from .OutputWindow import OutputWindow
31from .configHandler import idleConf
32from . import idlever
33from . import rpc
34from . import Debugger
35from . import RemoteDebugger
36from . import macosxSupport
Chui Tey5d2af632002-05-26 13:36:41 +000037
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000038IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000039LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000040
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000041try:
42 from signal import SIGTERM
43except ImportError:
44 SIGTERM = 15
45
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000046# Override warnings module to write to warning_stream. Initialize to send IDLE
47# internal warnings to the console. ScriptBinding.check_syntax() will
48# temporarily redirect the stream to the shell window to display warnings when
49# checking user's code.
50global warning_stream
51warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000052try:
53 import warnings
54except ImportError:
55 pass
56else:
57 def idle_showwarning(message, category, filename, lineno):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000058 file = warning_stream
59 try:
60 file.write(warnings.formatwarning(message, category, filename, lineno))
61 except IOError:
62 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000063 warnings.showwarning = idle_showwarning
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000064 def idle_formatwarning(message, category, filename, lineno):
65 """Format warnings the IDLE way"""
66 s = "\nWarning (from warnings module):\n"
67 s += ' File \"%s\", line %s\n' % (filename, lineno)
68 line = linecache.getline(filename, lineno).strip()
69 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()
81 (which destroys them), and then restore the saved entries.
82
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
86 """
David Scherer7aced172000-08-15 01:13:23 +000087 cache = linecache.cache
88 save = {}
89 for filename in cache.keys():
90 if filename[:1] + filename[-1:] == '<>':
91 save[filename] = cache[filename]
92 orig_checkcache()
93 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000094
Kurt B. Kaiser81885592002-11-29 22:10:53 +000095# Patch linecache.checkcache():
96linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000097
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000098
David Scherer7aced172000-08-15 01:13:23 +000099class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000100 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000101
David Scherer7aced172000-08-15 01:13:23 +0000102 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000103 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000104 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000105 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000106 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000107 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
108
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000109 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
110 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000111 # whenever a file is changed, restore breakpoints
112 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000113 def filename_changed_hook(old_hook=self.io.filename_change_hook,
114 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000115 self.restore_file_breaks()
116 old_hook()
117 self.io.set_filename_change_hook(filename_changed_hook)
118
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000119 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
120 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000121
Chui Teya2adb0f2002-11-04 22:14:54 +0000122 def set_breakpoint(self, lineno):
123 text = self.text
124 filename = self.io.filename
125 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
126 try:
127 i = self.breakpoints.index(lineno)
128 except ValueError: # only add if missing, i.e. do once
129 self.breakpoints.append(lineno)
130 try: # update the subprocess debugger
131 debug = self.flist.pyshell.interp.debugger
132 debug.set_breakpoint_here(filename, lineno)
133 except: # but debugger may not be active right now....
134 pass
135
David Scherer7aced172000-08-15 01:13:23 +0000136 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000137 text = self.text
138 filename = self.io.filename
139 if not filename:
140 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000141 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000142 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000143 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000144
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000145 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000146 text = self.text
147 filename = self.io.filename
148 if not filename:
149 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000150 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000151 lineno = int(float(text.index("insert")))
152 try:
153 self.breakpoints.remove(lineno)
154 except:
155 pass
156 text.tag_remove("BREAK", "insert linestart",\
157 "insert lineend +1char")
158 try:
159 debug = self.flist.pyshell.interp.debugger
160 debug.clear_breakpoint_here(filename, lineno)
161 except:
162 pass
163
164 def clear_file_breaks(self):
165 if self.breakpoints:
166 text = self.text
167 filename = self.io.filename
168 if not filename:
169 text.bell()
170 return
171 self.breakpoints = []
172 text.tag_remove("BREAK", "1.0", END)
173 try:
174 debug = self.flist.pyshell.interp.debugger
175 debug.clear_file_breaks(filename)
176 except:
177 pass
178
Chui Teya2adb0f2002-11-04 22:14:54 +0000179 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000180 "Save breakpoints when file is saved"
181 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
182 # be run. The breaks are saved at that time. If we introduce
183 # a temporary file save feature the save breaks functionality
184 # needs to be re-verified, since the breaks at the time the
185 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000186 # permanent save of the file. Currently, a break introduced
187 # after a save will be effective, but not persistent.
188 # This is necessary to keep the saved breaks synched with the
189 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000190 #
191 # Breakpoints are set as tagged ranges in the text. Certain
192 # kinds of edits cause these ranges to be deleted: Inserting
193 # or deleting a line just before a breakpoint, and certain
194 # deletions prior to a breakpoint. These issues need to be
195 # investigated and understood. It's not clear if they are
196 # Tk issues or IDLE issues, or whether they can actually
197 # be fixed. Since a modified file has to be saved before it is
198 # run, and since self.breakpoints (from which the subprocess
199 # debugger is loaded) is updated during the save, the visible
200 # breaks stay synched with the subprocess even if one of these
201 # unexpected breakpoint deletions occurs.
202 breaks = self.breakpoints
203 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000204 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000205 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000206 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000207 lines = []
208 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000211 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000212 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 new_file.close()
217
218 def restore_file_breaks(self):
219 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000220 filename = self.io.filename
221 if filename is None:
222 return
Chui Tey69371d62002-11-04 23:39:45 +0000223 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000224 lines = open(self.breakpointPath,"r").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 None: idleConf.GetHighlight(theme, "normal"),
302 })
David Scherer7aced172000-08-15 01:13:23 +0000303
David Scherer7aced172000-08-15 01:13:23 +0000304class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000305 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000306
307 def insert(self, index, chars, tags=None):
308 try:
309 if self.delegate.compare(index, "<", "iomark"):
310 self.delegate.bell()
311 return
312 except TclError:
313 pass
314 UndoDelegator.insert(self, index, chars, tags)
315
316 def delete(self, index1, index2=None):
317 try:
318 if self.delegate.compare(index1, "<", "iomark"):
319 self.delegate.bell()
320 return
321 except TclError:
322 pass
323 UndoDelegator.delete(self, index1, index2)
324
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000325
326class MyRPCClient(rpc.RPCClient):
327
328 def handle_EOF(self):
329 "Override the base class - just re-raise EOFError"
330 raise EOFError
331
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000332
David Scherer7aced172000-08-15 01:13:23 +0000333class ModifiedInterpreter(InteractiveInterpreter):
334
335 def __init__(self, tkconsole):
336 self.tkconsole = tkconsole
337 locals = sys.modules['__main__'].__dict__
338 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000339 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000340 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000341 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000342
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000343 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000344 rpcclt = None
345 rpcpid = None
346
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000347 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000348 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000349 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000350
Tony Lowndsf53dec22002-12-20 04:24:43 +0000351 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000352 w = ['-W' + s for s in sys.warnoptions]
353 # Maybe IDLE is installed and is being accessed via sys.path,
354 # or maybe it's not installed and the idle.py script is being
355 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000356 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
357 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000358 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000359 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000360 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000361 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000362 if sys.platform[:3] == 'win' and ' ' in sys.executable:
363 # handle embedded space in path by quoting the argument
364 decorated_exec = '"%s"' % sys.executable
365 else:
366 decorated_exec = sys.executable
367 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000368
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000369 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000370 # spawning first avoids passing a listening socket to the subprocess
371 self.spawn_subprocess()
372 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000373 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000374 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000375 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000376 time.sleep(i)
377 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000378 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000379 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000380 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000381 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000382 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000383 self.display_port_binding_error()
384 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000385 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000386 self.rpcclt.listening_sock.settimeout(10)
387 try:
388 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000389 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000390 self.display_no_subprocess_error()
391 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000392 self.rpcclt.register("stdin", self.tkconsole)
393 self.rpcclt.register("stdout", self.tkconsole.stdout)
394 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000395 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000396 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000397 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000398 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000399 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000400 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000401
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000402 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000403 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000404 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000405 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000406 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000407 debug = self.getdebugger()
408 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000409 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000410 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000411 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
412 except:
413 pass
414 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000415 self.rpcclt.close()
416 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000417 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000418 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000419 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000420 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000421 try:
422 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000423 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000424 self.display_no_subprocess_error()
425 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000426 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000427 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000428 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000429 if was_executing:
430 console.write('\n')
431 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000432 halfbar = ((int(console.width) - 16) // 2) * '='
433 console.write(halfbar + ' RESTART ' + halfbar)
434 console.text.mark_set("restart", "end-1c")
435 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000436 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000437 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000438 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000439 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000440 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000441 # reload remote debugger breakpoints for all PyShellEditWindows
442 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000443 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000444 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000445
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000446 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000447 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000448
449 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000450 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000452 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000453 try:
454 self.rpcclt.close()
455 except AttributeError: # no socket
456 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000457 self.unix_terminate()
458 self.tkconsole.executing = False
459 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000460
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000461 def unix_terminate(self):
462 "UNIX: make sure subprocess is terminated and collect status"
463 if hasattr(os, 'kill'):
464 try:
465 os.kill(self.rpcpid, SIGTERM)
466 except OSError:
467 # process already terminated:
468 return
469 else:
470 try:
471 os.waitpid(self.rpcpid, 0)
472 except OSError:
473 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000474
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000475 def transfer_path(self):
476 self.runcommand("""if 1:
477 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000478 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000479 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000480 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000481
Chui Tey5d2af632002-05-26 13:36:41 +0000482 active_seq = None
483
484 def poll_subprocess(self):
485 clt = self.rpcclt
486 if clt is None:
487 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000488 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000489 response = clt.pollresponse(self.active_seq, wait=0.05)
490 except (EOFError, IOError, KeyboardInterrupt):
491 # lost connection or subprocess terminated itself, restart
492 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000493 if self.tkconsole.closing:
494 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000495 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000496 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000497 if response:
498 self.tkconsole.resetoutput()
499 self.active_seq = None
500 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000501 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000502 if how == "OK":
503 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000504 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000505 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000506 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
507 self.remote_stack_viewer()
508 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000509 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000510 print(errmsg, what, file=sys.__stderr__)
511 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000512 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000513 try:
514 self.tkconsole.endexecuting()
515 except AttributeError: # shell may have closed
516 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000517 # Reschedule myself
518 if not self.tkconsole.closing:
519 self.tkconsole.text.after(self.tkconsole.pollinterval,
520 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000521
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000522 debugger = None
523
524 def setdebugger(self, debugger):
525 self.debugger = debugger
526
527 def getdebugger(self):
528 return self.debugger
529
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000530 def open_remote_stack_viewer(self):
531 """Initiate the remote stack viewer from a separate thread.
532
533 This method is called from the subprocess, and by returning from this
534 method we allow the subprocess to unblock. After a bit the shell
535 requests the subprocess to open the remote stack viewer which returns a
536 static object looking at the last exceptiopn. It is queried through
537 the RPC mechanism.
538
539 """
540 self.tkconsole.text.after(300, self.remote_stack_viewer)
541 return
542
Chui Tey5d2af632002-05-26 13:36:41 +0000543 def remote_stack_viewer(self):
Guido van Rossum36e0a922007-07-20 04:05:57 +0000544 from . import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000545 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000546 if oid is None:
547 self.tkconsole.root.bell()
548 return
549 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Guido van Rossum36e0a922007-07-20 04:05:57 +0000550 from .TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000551 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000552 theme = idleConf.GetOption('main','Theme','name')
553 background = idleConf.GetHighlight(theme, 'normal')['background']
554 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000555 sc.frame.pack(expand=1, fill="both")
556 node = TreeNode(sc.canvas, None, item)
557 node.expand()
558 # XXX Should GC the remote tree when closing the window
559
David Scherer7aced172000-08-15 01:13:23 +0000560 gid = 0
561
562 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000563 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000564 filename = self.stuffsource(source)
565 self.execfile(filename, source)
566
567 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000568 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000569 if source is None:
570 source = open(filename, "r").read()
571 try:
572 code = compile(source, filename, "exec")
573 except (OverflowError, SyntaxError):
574 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000575 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000576 print('*** Error in script or command!\n', file=tkerr)
577 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000578 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000579 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000580 else:
581 self.runcode(code)
582
583 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000584 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000585 filename = self.stuffsource(source)
586 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000587 self.save_warnings_filters = warnings.filters[:]
588 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000589 if isinstance(source, types.UnicodeType):
Guido van Rossum36e0a922007-07-20 04:05:57 +0000590 from . import IOBinding
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000591 try:
592 source = source.encode(IOBinding.encoding)
593 except UnicodeError:
594 self.tkconsole.resetoutput()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000595 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000596 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000597 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000598 # InteractiveInterpreter.runsource() calls its runcode() method,
599 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000600 return InteractiveInterpreter.runsource(self, source, filename)
601 finally:
602 if self.save_warnings_filters is not None:
603 warnings.filters[:] = self.save_warnings_filters
604 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000605
606 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000607 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000608 filename = "<pyshell#%d>" % self.gid
609 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000610 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000611 linecache.cache[filename] = len(source)+1, 0, lines, filename
612 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000613
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000614 def prepend_syspath(self, filename):
615 "Prepend sys.path with file's directory if not already included"
616 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000617 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000618 import sys as _sys
619 from os.path import dirname as _dirname
620 _dir = _dirname(_filename)
621 if not _dir in _sys.path:
622 _sys.path.insert(0, _dir)
623 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000624 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000625
David Scherer7aced172000-08-15 01:13:23 +0000626 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000627 """Extend base class method: Add Colorizing
628
629 Color the offending position instead of printing it and pointing at it
630 with a caret.
631
632 """
David Scherer7aced172000-08-15 01:13:23 +0000633 text = self.tkconsole.text
634 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000635 if stuff:
636 msg, lineno, offset, line = stuff
637 if lineno == 1:
638 pos = "iomark + %d chars" % (offset-1)
639 else:
640 pos = "iomark linestart + %d lines + %d chars" % \
641 (lineno-1, offset-1)
642 text.tag_add("ERROR", pos)
643 text.see(pos)
644 char = text.get(pos)
645 if char and char in IDENTCHARS:
646 text.tag_add("ERROR", pos + " wordstart", pos)
647 self.tkconsole.resetoutput()
648 self.write("SyntaxError: %s\n" % str(msg))
649 else:
David Scherer7aced172000-08-15 01:13:23 +0000650 self.tkconsole.resetoutput()
651 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000652 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000653
654 def unpackerror(self):
655 type, value, tb = sys.exc_info()
656 ok = type is SyntaxError
657 if ok:
658 try:
659 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000660 if not offset:
661 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000662 except:
663 ok = 0
664 if ok:
665 return msg, lineno, offset, line
666 else:
667 return None
668
669 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000670 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000671 self.tkconsole.resetoutput()
672 self.checklinecache()
673 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000674 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
675 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000676
677 def checklinecache(self):
678 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000679 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000680 if key[:1] + key[-1:] != "<>":
681 del c[key]
682
Chui Tey5d2af632002-05-26 13:36:41 +0000683 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000684 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000685 # The code better not raise an exception!
686 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000687 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000688 return 0
689 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000690 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000691 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000692 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000693 return 1
694
David Scherer7aced172000-08-15 01:13:23 +0000695 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000696 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000697 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000698 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000699 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000700 if self.save_warnings_filters is not None:
701 warnings.filters[:] = self.save_warnings_filters
702 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000703 debugger = self.debugger
704 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000705 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000706 if not debugger and self.rpcclt is not None:
707 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
708 (code,), {})
709 elif debugger:
710 debugger.run(code, self.locals)
711 else:
712 exec(code, self.locals)
713 except SystemExit:
714 if not self.tkconsole.closing:
715 if tkMessageBox.askyesno(
716 "Exit?",
717 "Do you want to exit altogether?",
718 default="yes",
719 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000720 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000721 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000722 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000723 else:
724 raise
725 except:
726 if use_subprocess:
727 print("IDLE internal error in runcode()",
728 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000729 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000730 self.tkconsole.endexecuting()
731 else:
732 if self.tkconsole.canceled:
733 self.tkconsole.canceled = False
734 print("KeyboardInterrupt", file=self.tkconsole.stderr)
735 else:
736 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000737 finally:
738 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000739 try:
740 self.tkconsole.endexecuting()
741 except AttributeError: # shell may have closed
742 pass
David Scherer7aced172000-08-15 01:13:23 +0000743
744 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000745 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000746 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000747
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000748 def display_port_binding_error(self):
749 tkMessageBox.showerror(
750 "Port Binding Error",
751 "IDLE can't bind TCP/IP port 8833, which is necessary to "
752 "communicate with its Python execution server. Either "
753 "no networking is installed on this computer or another "
754 "process (another IDLE?) is using the port. Run IDLE with the -n "
755 "command line switch to start without a subprocess and refer to "
756 "Help/IDLE Help 'Running without a subprocess' for further "
757 "details.",
758 master=self.tkconsole.text)
759
760 def display_no_subprocess_error(self):
761 tkMessageBox.showerror(
762 "Subprocess Startup Error",
763 "IDLE's subprocess didn't make connection. Either IDLE can't "
764 "start a subprocess or personal firewall software is blocking "
765 "the connection.",
766 master=self.tkconsole.text)
767
768 def display_executing_dialog(self):
769 tkMessageBox.showerror(
770 "Already executing",
771 "The Python Shell window is already executing a command; "
772 "please wait until it is finished.",
773 master=self.tkconsole.text)
774
775
David Scherer7aced172000-08-15 01:13:23 +0000776class PyShell(OutputWindow):
777
778 shell_title = "Python Shell"
779
780 # Override classes
781 ColorDelegator = ModifiedColorDelegator
782 UndoDelegator = ModifiedUndoDelegator
783
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000784 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000785 menu_specs = [
786 ("file", "_File"),
787 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000788 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000789 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000790 ("windows", "_Windows"),
791 ("help", "_Help"),
792 ]
David Scherer7aced172000-08-15 01:13:23 +0000793
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000794 if macosxSupport.runningAsOSXApp():
795 del menu_specs[-3]
796 menu_specs[-2] = ("windows", "_Window")
797
798
David Scherer7aced172000-08-15 01:13:23 +0000799 # New classes
Guido van Rossum36e0a922007-07-20 04:05:57 +0000800 from .IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000801
802 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000803 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000804 ms = self.menu_specs
805 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000806 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000807 self.interp = ModifiedInterpreter(self)
808 if flist is None:
809 root = Tk()
810 fixwordbreaks(root)
811 root.withdraw()
812 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000813 #
David Scherer7aced172000-08-15 01:13:23 +0000814 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000815 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000816## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
817 self.usetabs = True
818 # indentwidth must be 8 when using tabs. See note in EditorWindow:
819 self.indentwidth = 8
820 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000821 #
David Scherer7aced172000-08-15 01:13:23 +0000822 text = self.text
823 text.configure(wrap="char")
824 text.bind("<<newline-and-indent>>", self.enter_callback)
825 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
826 text.bind("<<interrupt-execution>>", self.cancel_callback)
827 text.bind("<<beginning-of-line>>", self.home_callback)
828 text.bind("<<end-of-file>>", self.eof_callback)
829 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000830 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000831 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000832 if use_subprocess:
833 text.bind("<<view-restart>>", self.view_restart_mark)
834 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000835 #
David Scherer7aced172000-08-15 01:13:23 +0000836 self.save_stdout = sys.stdout
837 self.save_stderr = sys.stderr
838 self.save_stdin = sys.stdin
Guido van Rossum36e0a922007-07-20 04:05:57 +0000839 from . import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000840 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
841 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
842 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000843 if not use_subprocess:
844 sys.stdout = self.stdout
845 sys.stderr = self.stderr
846 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000847 #
David Scherer7aced172000-08-15 01:13:23 +0000848 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000849 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000850 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000851
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000852 def get_standard_extension_names(self):
853 return idleConf.GetExtensions(shell_only=True)
854
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000855 reading = False
856 executing = False
857 canceled = False
858 endoffile = False
859 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000860
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000861 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000862 global warning_stream
863 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000864
865 def get_warning_stream(self):
866 return warning_stream
867
David Scherer7aced172000-08-15 01:13:23 +0000868 def toggle_debugger(self, event=None):
869 if self.executing:
870 tkMessageBox.showerror("Don't debug now",
871 "You can only toggle the debugger when idle",
872 master=self.text)
873 self.set_debugger_indicator()
874 return "break"
875 else:
876 db = self.interp.getdebugger()
877 if db:
878 self.close_debugger()
879 else:
880 self.open_debugger()
881
882 def set_debugger_indicator(self):
883 db = self.interp.getdebugger()
884 self.setvar("<<toggle-debugger>>", not not db)
885
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000886 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000887 pass # All we need is the variable
888
889 def close_debugger(self):
890 db = self.interp.getdebugger()
891 if db:
892 self.interp.setdebugger(None)
893 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000894 if self.interp.rpcclt:
895 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000896 self.resetoutput()
897 self.console.write("[DEBUG OFF]\n")
898 sys.ps1 = ">>> "
899 self.showprompt()
900 self.set_debugger_indicator()
901
902 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000903 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000904 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
905 self)
906 else:
907 dbg_gui = Debugger.Debugger(self)
908 self.interp.setdebugger(dbg_gui)
909 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000910 sys.ps1 = "[DEBUG ON]\n>>> "
911 self.showprompt()
912 self.set_debugger_indicator()
913
David Scherer7aced172000-08-15 01:13:23 +0000914 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000915 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000916 self.resetoutput()
917 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000918
919 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000920 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000921 self.executing = 0
922 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000923 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000924
925 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000926 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000927 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000928 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000929 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000930 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000931 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000932 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000933 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000934 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000935 if self.reading:
936 self.top.quit()
937 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000938 self.closing = True
939 # Wait for poll_subprocess() rescheduling to stop
940 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000941
942 def close2(self):
943 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000944
945 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000946 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000947 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000948 if use_subprocess:
949 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000950 # Restore std streams
951 sys.stdout = self.save_stdout
952 sys.stderr = self.save_stderr
953 sys.stdin = self.save_stdin
954 # Break cycles
955 self.interp = None
956 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000957 self.flist.pyshell = None
958 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000959 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000960
961 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000962 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000963 return True
David Scherer7aced172000-08-15 01:13:23 +0000964
965 def short_title(self):
966 return self.shell_title
967
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000968 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000969 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000970
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000971 firewallmessage = """
972 ****************************************************************
973 Personal firewall software may warn about the connection IDLE
974 makes to its subprocess using this computer's internal loopback
975 interface. This connection is not visible on any external
976 interface and no data is sent to or received from the Internet.
977 ****************************************************************
978 """
979
David Scherer7aced172000-08-15 01:13:23 +0000980 def begin(self):
981 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000982 if use_subprocess:
983 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000984 client = self.interp.start_subprocess()
985 if not client:
986 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000987 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000988 else:
989 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000990 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000991 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000992 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000993 self.showprompt()
994 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000995 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000996 return True
David Scherer7aced172000-08-15 01:13:23 +0000997
998 def readline(self):
999 save = self.reading
1000 try:
1001 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001002 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001003 finally:
1004 self.reading = save
1005 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001006 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1007 line = "\n"
Guido van Rossumef87d6e2007-05-02 19:09:54 +00001008 if isinstance(line, str):
Guido van Rossum36e0a922007-07-20 04:05:57 +00001009 from . import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001010 try:
1011 line = line.encode(IOBinding.encoding)
1012 except UnicodeError:
1013 pass
David Scherer7aced172000-08-15 01:13:23 +00001014 self.resetoutput()
1015 if self.canceled:
1016 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001017 if not use_subprocess:
1018 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001019 if self.endoffile:
1020 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001021 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001022 return line
1023
1024 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001025 return True
David Scherer7aced172000-08-15 01:13:23 +00001026
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001027 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001028 try:
1029 if self.text.compare("sel.first", "!=", "sel.last"):
1030 return # Active selection -- always use default binding
1031 except:
1032 pass
1033 if not (self.executing or self.reading):
1034 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001035 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001036 self.showprompt()
1037 return "break"
1038 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001039 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001040 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001041 if self.interp.getdebugger():
1042 self.interp.restart_subprocess()
1043 else:
1044 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001045 if self.reading:
1046 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001047 return "break"
1048
1049 def eof_callback(self, event):
1050 if self.executing and not self.reading:
1051 return # Let the default binding (delete next char) take over
1052 if not (self.text.compare("iomark", "==", "insert") and
1053 self.text.compare("insert", "==", "end-1c")):
1054 return # Let the default binding (delete next char) take over
1055 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001056 self.resetoutput()
1057 self.close()
1058 else:
1059 self.canceled = 0
1060 self.endoffile = 1
1061 self.top.quit()
1062 return "break"
1063
1064 def home_callback(self, event):
1065 if event.state != 0 and event.keysym == "Home":
1066 return # <Modifier-Home>; fall back to class binding
1067 if self.text.compare("iomark", "<=", "insert") and \
1068 self.text.compare("insert linestart", "<=", "iomark"):
1069 self.text.mark_set("insert", "iomark")
1070 self.text.tag_remove("sel", "1.0", "end")
1071 self.text.see("insert")
1072 return "break"
1073
1074 def linefeed_callback(self, event):
1075 # Insert a linefeed without entering anything (still autoindented)
1076 if self.reading:
1077 self.text.insert("insert", "\n")
1078 self.text.see("insert")
1079 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001080 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001081 return "break"
1082
1083 def enter_callback(self, event):
1084 if self.executing and not self.reading:
1085 return # Let the default binding (insert '\n') take over
1086 # If some text is selected, recall the selection
1087 # (but only if this before the I/O mark)
1088 try:
1089 sel = self.text.get("sel.first", "sel.last")
1090 if sel:
1091 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001092 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001093 return "break"
1094 except:
1095 pass
1096 # If we're strictly before the line containing iomark, recall
1097 # the current line, less a leading prompt, less leading or
1098 # trailing whitespace
1099 if self.text.compare("insert", "<", "iomark linestart"):
1100 # Check if there's a relevant stdin range -- if so, use it
1101 prev = self.text.tag_prevrange("stdin", "insert")
1102 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001103 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001104 return "break"
1105 next = self.text.tag_nextrange("stdin", "insert")
1106 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001107 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001108 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001109 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001110 indices = self.text.tag_nextrange("console", "insert linestart")
1111 if indices and \
1112 self.text.compare(indices[0], "<=", "insert linestart"):
1113 self.recall(self.text.get(indices[1], "insert lineend"), event)
1114 else:
1115 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001116 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001117 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001118 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001119 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001120 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001121 # If we're in the current input and there's only whitespace
1122 # beyond the cursor, erase that whitespace first
1123 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001124 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001125 self.text.delete("insert", "end-1c")
1126 # If we're in the current input before its last line,
1127 # insert a newline right at the insert point
1128 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001129 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001130 return "break"
1131 # We're in the last line; append a newline and submit it
1132 self.text.mark_set("insert", "end-1c")
1133 if self.reading:
1134 self.text.insert("insert", "\n")
1135 self.text.see("insert")
1136 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001137 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001138 self.text.tag_add("stdin", "iomark", "end-1c")
1139 self.text.update_idletasks()
1140 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001141 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001142 else:
1143 self.runit()
1144 return "break"
1145
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001146 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001147 # remove leading and trailing empty or whitespace lines
1148 s = re.sub(r'^\s*\n', '' , s)
1149 s = re.sub(r'\n\s*$', '', s)
1150 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001151 self.text.undo_block_start()
1152 try:
1153 self.text.tag_remove("sel", "1.0", "end")
1154 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001155 prefix = self.text.get("insert linestart", "insert")
1156 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001157 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001158 prefix = self.text.get("insert linestart", "insert")
1159 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001160 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001161 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1162 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001163 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001164 if line.startswith(orig_base_indent):
1165 # replace orig base indentation with new indentation
1166 line = new_base_indent + line[len(orig_base_indent):]
1167 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001168 finally:
1169 self.text.see("insert")
1170 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001171
1172 def runit(self):
1173 line = self.text.get("iomark", "end-1c")
1174 # Strip off last newline and surrounding whitespace.
1175 # (To allow you to hit return twice to end a statement.)
1176 i = len(line)
1177 while i > 0 and line[i-1] in " \t":
1178 i = i-1
1179 if i > 0 and line[i-1] == "\n":
1180 i = i-1
1181 while i > 0 and line[i-1] in " \t":
1182 i = i-1
1183 line = line[:i]
1184 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001185
David Scherer7aced172000-08-15 01:13:23 +00001186 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001187 if self.interp.rpcclt:
1188 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001189 try:
1190 sys.last_traceback
1191 except:
1192 tkMessageBox.showerror("No stack trace",
1193 "There is no stack trace yet.\n"
1194 "(sys.last_traceback is not defined)",
1195 master=self.text)
1196 return
Guido van Rossum36e0a922007-07-20 04:05:57 +00001197 from .StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001198 sv = StackBrowser(self.root, self.flist)
1199
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001200 def view_restart_mark(self, event=None):
1201 self.text.see("iomark")
1202 self.text.see("restart")
1203
1204 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001205 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001206
David Scherer7aced172000-08-15 01:13:23 +00001207 def showprompt(self):
1208 self.resetoutput()
1209 try:
1210 s = str(sys.ps1)
1211 except:
1212 s = ""
1213 self.console.write(s)
1214 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001215 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001216 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001217
1218 def resetoutput(self):
1219 source = self.text.get("iomark", "end-1c")
1220 if self.history:
1221 self.history.history_store(source)
1222 if self.text.get("end-2c") != "\n":
1223 self.text.insert("end-1c", "\n")
1224 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001225 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001226
1227 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001228 try:
1229 self.text.mark_gravity("iomark", "right")
1230 OutputWindow.write(self, s, tags, "iomark")
1231 self.text.mark_gravity("iomark", "left")
1232 except:
1233 pass
David Scherer7aced172000-08-15 01:13:23 +00001234 if self.canceled:
1235 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001236 if not use_subprocess:
1237 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001238
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001239class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001240
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001241 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001242 self.shell = shell
1243 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001244 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001245
1246 def write(self, s):
1247 self.shell.write(s, self.tags)
1248
1249 def writelines(self, l):
1250 map(self.write, l)
1251
1252 def flush(self):
1253 pass
1254
1255 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001256 return True
David Scherer7aced172000-08-15 01:13:23 +00001257
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001258
David Scherer7aced172000-08-15 01:13:23 +00001259usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001260
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001261USAGE: idle [-deins] [-t title] [file]*
1262 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1263 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001264
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001265 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001266 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001267
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001268The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001269
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001270 -e open an edit window
1271 -i open a shell window
1272
1273The following options imply -i and will open a shell:
1274
1275 -c cmd run the command in a shell, or
1276 -r file run script from file
1277
1278 -d enable the debugger
1279 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1280 -t title set title of shell window
1281
1282A default edit window will be bypassed when -c, -r, or - are used.
1283
1284[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1285
1286Examples:
1287
1288idle
1289 Open an edit window or shell depending on IDLE's configuration.
1290
1291idle foo.py foobar.py
1292 Edit the files, also open a shell if configured to start with shell.
1293
1294idle -est "Baz" foo.py
1295 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1296 window with the title "Baz".
1297
1298idle -c "import sys; print sys.argv" "foo"
1299 Open a shell window and run the command, passing "-c" in sys.argv[0]
1300 and "foo" in sys.argv[1].
1301
1302idle -d -s -r foo.py "Hello World"
1303 Open a shell window, run a startup script, enable the debugger, and
1304 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1305 sys.argv[1].
1306
1307echo "import sys; print sys.argv" | idle - "foobar"
1308 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1309 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001310"""
1311
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001312def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001313 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001314
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001315 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001316 enable_shell = False
1317 enable_edit = False
1318 debug = False
1319 cmd = None
1320 script = None
1321 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001322 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001323 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001324 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001325 sys.stderr.write("Error: %s\n" % str(msg))
1326 sys.stderr.write(usage_msg)
1327 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001328 for o, a in opts:
1329 if o == '-c':
1330 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001331 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001332 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001333 debug = True
1334 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001335 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001336 enable_edit = True
1337 if o == '-h':
1338 sys.stdout.write(usage_msg)
1339 sys.exit()
1340 if o == '-i':
1341 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001342 if o == '-n':
1343 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001344 if o == '-r':
1345 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001346 if os.path.isfile(script):
1347 pass
1348 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001349 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001350 sys.exit()
1351 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001352 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001353 startup = True
1354 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001355 if o == '-t':
1356 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001357 enable_shell = True
1358 if args and args[0] == '-':
1359 cmd = sys.stdin.read()
1360 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001361 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001362 for i in range(len(sys.path)):
1363 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 if args and args[0] == '-':
1365 sys.argv = [''] + args[1:]
1366 elif cmd:
1367 sys.argv = ['-c'] + args
1368 elif script:
1369 sys.argv = [script] + args
1370 elif args:
1371 enable_edit = True
1372 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001373 for filename in args:
1374 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001375 for dir in pathx:
1376 dir = os.path.abspath(dir)
1377 if not dir in sys.path:
1378 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001379 else:
1380 dir = os.getcwd()
1381 if not dir in sys.path:
1382 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001383 # check the IDLE settings configuration (but command line overrides)
1384 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001385 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001386 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001387 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001388 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001389 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001390
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001391 fixwordbreaks(root)
1392 root.withdraw()
1393 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001394 macosxSupport.setupApp(root, flist)
1395
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001396 if enable_edit:
1397 if not (cmd or script):
1398 for filename in args:
1399 flist.open(filename)
1400 if not args:
1401 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001402 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001403 shell = flist.open_shell()
1404 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001405 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001406
1407 if macosxSupport.runningAsOSXApp() and flist.dict:
1408 # On OSX: when the user has double-clicked on a file that causes
1409 # IDLE to be launched the shell window will open just in front of
1410 # the file she wants to see. Lower the interpreter window when
1411 # there are open files.
1412 shell.top.lower()
1413
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001414 shell = flist.pyshell
1415 # handle remaining options:
1416 if debug:
1417 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001418 if startup:
1419 filename = os.environ.get("IDLESTARTUP") or \
1420 os.environ.get("PYTHONSTARTUP")
1421 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001422 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001423 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001424 shell.interp.runcommand("""if 1:
1425 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001426 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001427 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001428 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001429 if cmd:
1430 shell.interp.execsource(cmd)
1431 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001432 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001433 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001434
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001435 root.mainloop()
1436 root.destroy()
1437
David Scherer7aced172000-08-15 01:13:23 +00001438if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001439 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001440 main()