blob: 2d69157b1ae952a759255eb4d7795c1bd62881b2 [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
Thomas Wouters0e3f5912006-08-11 14:57:12 +000014import macosxSupport
David Scherer7aced172000-08-15 01:13:23 +000015
16import linecache
17from code import InteractiveInterpreter
18
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000019try:
20 from Tkinter import *
21except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000022 print("** IDLE can't import Tkinter. " \
23 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000024 sys.exit(1)
David Scherer7aced172000-08-15 01:13:23 +000025import tkMessageBox
26
27from EditorWindow import EditorWindow, fixwordbreaks
28from FileList import FileList
29from ColorDelegator import ColorDelegator
30from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000031from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000032from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000033import idlever
34
Chui Tey5d2af632002-05-26 13:36:41 +000035import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000036import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000037import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000038
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000039IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000040LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000041
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000042try:
43 from signal import SIGTERM
44except ImportError:
45 SIGTERM = 15
46
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000047# Override warnings module to write to warning_stream. Initialize to send IDLE
48# internal warnings to the console. ScriptBinding.check_syntax() will
49# temporarily redirect the stream to the shell window to display warnings when
50# checking user's code.
51global warning_stream
52warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000053try:
54 import warnings
55except ImportError:
56 pass
57else:
58 def idle_showwarning(message, category, filename, lineno):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000059 file = warning_stream
60 try:
61 file.write(warnings.formatwarning(message, category, filename, lineno))
62 except IOError:
63 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000064 warnings.showwarning = idle_showwarning
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000065 def idle_formatwarning(message, category, filename, lineno):
66 """Format warnings the IDLE way"""
67 s = "\nWarning (from warnings module):\n"
68 s += ' File \"%s\", line %s\n' % (filename, lineno)
69 line = linecache.getline(filename, lineno).strip()
70 if line:
71 s += " %s\n" % line
72 s += "%s: %s\n>>> " % (category.__name__, message)
73 return s
74 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000075
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000076def extended_linecache_checkcache(filename=None,
77 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000078 """Extend linecache.checkcache to preserve the <pyshell#...> entries
79
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000080 Rather than repeating the linecache code, patch it to save the
81 <pyshell#...> entries, call the original linecache.checkcache()
82 (which destroys them), and then restore the saved entries.
83
84 orig_checkcache is bound at definition time to the original
85 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000086
87 """
David Scherer7aced172000-08-15 01:13:23 +000088 cache = linecache.cache
89 save = {}
90 for filename in cache.keys():
91 if filename[:1] + filename[-1:] == '<>':
92 save[filename] = cache[filename]
93 orig_checkcache()
94 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000095
Kurt B. Kaiser81885592002-11-29 22:10:53 +000096# Patch linecache.checkcache():
97linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000098
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000099
David Scherer7aced172000-08-15 01:13:23 +0000100class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000101 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000102
David Scherer7aced172000-08-15 01:13:23 +0000103 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000104 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000105 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000106 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000107 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000108 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
109
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000110 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
111 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000112 # whenever a file is changed, restore breakpoints
113 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000114 def filename_changed_hook(old_hook=self.io.filename_change_hook,
115 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000116 self.restore_file_breaks()
117 old_hook()
118 self.io.set_filename_change_hook(filename_changed_hook)
119
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000120 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
121 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000122
Chui Teya2adb0f2002-11-04 22:14:54 +0000123 def set_breakpoint(self, lineno):
124 text = self.text
125 filename = self.io.filename
126 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
127 try:
128 i = self.breakpoints.index(lineno)
129 except ValueError: # only add if missing, i.e. do once
130 self.breakpoints.append(lineno)
131 try: # update the subprocess debugger
132 debug = self.flist.pyshell.interp.debugger
133 debug.set_breakpoint_here(filename, lineno)
134 except: # but debugger may not be active right now....
135 pass
136
David Scherer7aced172000-08-15 01:13:23 +0000137 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000138 text = self.text
139 filename = self.io.filename
140 if not filename:
141 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000142 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000143 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000144 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000145
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000146 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000147 text = self.text
148 filename = self.io.filename
149 if not filename:
150 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000151 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000152 lineno = int(float(text.index("insert")))
153 try:
154 self.breakpoints.remove(lineno)
155 except:
156 pass
157 text.tag_remove("BREAK", "insert linestart",\
158 "insert lineend +1char")
159 try:
160 debug = self.flist.pyshell.interp.debugger
161 debug.clear_breakpoint_here(filename, lineno)
162 except:
163 pass
164
165 def clear_file_breaks(self):
166 if self.breakpoints:
167 text = self.text
168 filename = self.io.filename
169 if not filename:
170 text.bell()
171 return
172 self.breakpoints = []
173 text.tag_remove("BREAK", "1.0", END)
174 try:
175 debug = self.flist.pyshell.interp.debugger
176 debug.clear_file_breaks(filename)
177 except:
178 pass
179
Chui Teya2adb0f2002-11-04 22:14:54 +0000180 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000181 "Save breakpoints when file is saved"
182 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
183 # be run. The breaks are saved at that time. If we introduce
184 # a temporary file save feature the save breaks functionality
185 # needs to be re-verified, since the breaks at the time the
186 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000187 # permanent save of the file. Currently, a break introduced
188 # after a save will be effective, but not persistent.
189 # This is necessary to keep the saved breaks synched with the
190 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000191 #
192 # Breakpoints are set as tagged ranges in the text. Certain
193 # kinds of edits cause these ranges to be deleted: Inserting
194 # or deleting a line just before a breakpoint, and certain
195 # deletions prior to a breakpoint. These issues need to be
196 # investigated and understood. It's not clear if they are
197 # Tk issues or IDLE issues, or whether they can actually
198 # be fixed. Since a modified file has to be saved before it is
199 # run, and since self.breakpoints (from which the subprocess
200 # debugger is loaded) is updated during the save, the visible
201 # breaks stay synched with the subprocess even if one of these
202 # unexpected breakpoint deletions occurs.
203 breaks = self.breakpoints
204 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000205 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000206 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000207 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000208 lines = []
209 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000210 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000211 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000212 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000213 self.update_breakpoints()
214 breaks = self.breakpoints
215 if breaks:
216 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000217 new_file.close()
218
219 def restore_file_breaks(self):
220 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000221 filename = self.io.filename
222 if filename is None:
223 return
Chui Tey69371d62002-11-04 23:39:45 +0000224 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000226 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000227 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000228 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000229 for breakpoint_linenumber in breakpoint_linenumbers:
230 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000231
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000232 def update_breakpoints(self):
233 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000234 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000235 ranges = text.tag_ranges("BREAK")
236 linenumber_list = self.ranges_to_linenumbers(ranges)
237 self.breakpoints = linenumber_list
238
239 def ranges_to_linenumbers(self, ranges):
240 lines = []
241 for index in range(0, len(ranges), 2):
242 lineno = int(float(ranges[index]))
243 end = int(float(ranges[index+1]))
244 while lineno < end:
245 lines.append(lineno)
246 lineno += 1
247 return lines
248
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000249# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000250# def saved_change_hook(self):
251# "Extend base method - clear breaks if module is modified"
252# if not self.get_saved():
253# self.clear_file_breaks()
254# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000255
256 def _close(self):
257 "Extend base method - clear breaks when module is closed"
258 self.clear_file_breaks()
259 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000260
David Scherer7aced172000-08-15 01:13:23 +0000261
262class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000263 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000264
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000265 # override FileList's class variable, instances return PyShellEditorWindow
266 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000267 EditorWindow = PyShellEditorWindow
268
269 pyshell = None
270
271 def open_shell(self, event=None):
272 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000273 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000274 else:
275 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000276 if self.pyshell:
277 if not self.pyshell.begin():
278 return None
David Scherer7aced172000-08-15 01:13:23 +0000279 return self.pyshell
280
281
282class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000283 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000284
Steven M. Gavab77d3432002-03-02 07:16:21 +0000285 def __init__(self):
286 ColorDelegator.__init__(self)
287 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000288
289 def recolorize_main(self):
290 self.tag_remove("TODO", "1.0", "iomark")
291 self.tag_add("SYNC", "1.0", "iomark")
292 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000293
Steven M. Gavab77d3432002-03-02 07:16:21 +0000294 def LoadTagDefs(self):
295 ColorDelegator.LoadTagDefs(self)
296 theme = idleConf.GetOption('main','Theme','name')
297 self.tagdefs.update({
298 "stdin": {'background':None,'foreground':None},
299 "stdout": idleConf.GetHighlight(theme, "stdout"),
300 "stderr": idleConf.GetHighlight(theme, "stderr"),
301 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000302 None: idleConf.GetHighlight(theme, "normal"),
303 })
David Scherer7aced172000-08-15 01:13:23 +0000304
David Scherer7aced172000-08-15 01:13:23 +0000305class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000306 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000307
308 def insert(self, index, chars, tags=None):
309 try:
310 if self.delegate.compare(index, "<", "iomark"):
311 self.delegate.bell()
312 return
313 except TclError:
314 pass
315 UndoDelegator.insert(self, index, chars, tags)
316
317 def delete(self, index1, index2=None):
318 try:
319 if self.delegate.compare(index1, "<", "iomark"):
320 self.delegate.bell()
321 return
322 except TclError:
323 pass
324 UndoDelegator.delete(self, index1, index2)
325
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000326
327class MyRPCClient(rpc.RPCClient):
328
329 def handle_EOF(self):
330 "Override the base class - just re-raise EOFError"
331 raise EOFError
332
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000333
David Scherer7aced172000-08-15 01:13:23 +0000334class ModifiedInterpreter(InteractiveInterpreter):
335
336 def __init__(self, tkconsole):
337 self.tkconsole = tkconsole
338 locals = sys.modules['__main__'].__dict__
339 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000340 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000341 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000342 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000343
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000344 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000345 rpcclt = None
346 rpcpid = None
347
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000348 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000349 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000350 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000351
Tony Lowndsf53dec22002-12-20 04:24:43 +0000352 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000353 w = ['-W' + s for s in sys.warnoptions]
Thomas Wouters89f507f2006-12-13 04:49:30 +0000354 if 1/2 > 0: # account for new division
355 w.append('-Qnew')
Tony Lownds2398d572003-05-13 15:28:21 +0000356 # Maybe IDLE is installed and is being accessed via sys.path,
357 # or maybe it's not installed and the idle.py script is being
358 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000359 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
360 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000361 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000362 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000363 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000364 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000365 if sys.platform[:3] == 'win' and ' ' in sys.executable:
366 # handle embedded space in path by quoting the argument
367 decorated_exec = '"%s"' % sys.executable
368 else:
369 decorated_exec = sys.executable
370 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000371
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000372 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000373 # spawning first avoids passing a listening socket to the subprocess
374 self.spawn_subprocess()
375 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000376 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000377 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000378 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000379 time.sleep(i)
380 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000381 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000382 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000383 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000384 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000385 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000386 self.display_port_binding_error()
387 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000388 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000389 self.rpcclt.listening_sock.settimeout(10)
390 try:
391 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000392 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000393 self.display_no_subprocess_error()
394 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000395 self.rpcclt.register("stdin", self.tkconsole)
396 self.rpcclt.register("stdout", self.tkconsole.stdout)
397 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000398 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000399 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000400 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000401 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000402 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000403 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000404
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000405 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000406 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000407 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000408 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000409 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000410 debug = self.getdebugger()
411 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000412 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000413 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000414 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
415 except:
416 pass
417 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000418 self.rpcclt.close()
419 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000420 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000421 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000422 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000423 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000424 try:
425 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000426 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000427 self.display_no_subprocess_error()
428 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000429 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000430 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000431 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000432 if was_executing:
433 console.write('\n')
434 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000435 halfbar = ((int(console.width) - 16) // 2) * '='
436 console.write(halfbar + ' RESTART ' + halfbar)
437 console.text.mark_set("restart", "end-1c")
438 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000439 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000440 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000441 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000442 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000443 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000444 # reload remote debugger breakpoints for all PyShellEditWindows
445 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000446 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000447 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000448
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000449 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000450 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451
452 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000453 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000454
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000455 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000456 try:
457 self.rpcclt.close()
458 except AttributeError: # no socket
459 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000460 self.unix_terminate()
461 self.tkconsole.executing = False
462 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000463
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000464 def unix_terminate(self):
465 "UNIX: make sure subprocess is terminated and collect status"
466 if hasattr(os, 'kill'):
467 try:
468 os.kill(self.rpcpid, SIGTERM)
469 except OSError:
470 # process already terminated:
471 return
472 else:
473 try:
474 os.waitpid(self.rpcpid, 0)
475 except OSError:
476 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000477
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000478 def transfer_path(self):
479 self.runcommand("""if 1:
480 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000481 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000482 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000483 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000484
Chui Tey5d2af632002-05-26 13:36:41 +0000485 active_seq = None
486
487 def poll_subprocess(self):
488 clt = self.rpcclt
489 if clt is None:
490 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000491 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000492 response = clt.pollresponse(self.active_seq, wait=0.05)
493 except (EOFError, IOError, KeyboardInterrupt):
494 # lost connection or subprocess terminated itself, restart
495 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000496 if self.tkconsole.closing:
497 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000498 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000499 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000500 if response:
501 self.tkconsole.resetoutput()
502 self.active_seq = None
503 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000504 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000505 if how == "OK":
506 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000507 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000508 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000509 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
510 self.remote_stack_viewer()
511 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000512 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000513 print(errmsg, what, file=sys.__stderr__)
514 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000515 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000516 try:
517 self.tkconsole.endexecuting()
518 except AttributeError: # shell may have closed
519 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000520 # Reschedule myself
521 if not self.tkconsole.closing:
522 self.tkconsole.text.after(self.tkconsole.pollinterval,
523 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000524
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000525 debugger = None
526
527 def setdebugger(self, debugger):
528 self.debugger = debugger
529
530 def getdebugger(self):
531 return self.debugger
532
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000533 def open_remote_stack_viewer(self):
534 """Initiate the remote stack viewer from a separate thread.
535
536 This method is called from the subprocess, and by returning from this
537 method we allow the subprocess to unblock. After a bit the shell
538 requests the subprocess to open the remote stack viewer which returns a
539 static object looking at the last exceptiopn. It is queried through
540 the RPC mechanism.
541
542 """
543 self.tkconsole.text.after(300, self.remote_stack_viewer)
544 return
545
Chui Tey5d2af632002-05-26 13:36:41 +0000546 def remote_stack_viewer(self):
547 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000548 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000549 if oid is None:
550 self.tkconsole.root.bell()
551 return
552 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
553 from TreeWidget import ScrolledCanvas, TreeNode
554 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000555 theme = idleConf.GetOption('main','Theme','name')
556 background = idleConf.GetHighlight(theme, 'normal')['background']
557 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000558 sc.frame.pack(expand=1, fill="both")
559 node = TreeNode(sc.canvas, None, item)
560 node.expand()
561 # XXX Should GC the remote tree when closing the window
562
David Scherer7aced172000-08-15 01:13:23 +0000563 gid = 0
564
565 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000566 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000567 filename = self.stuffsource(source)
568 self.execfile(filename, source)
569
570 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000571 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000572 if source is None:
573 source = open(filename, "r").read()
574 try:
575 code = compile(source, filename, "exec")
576 except (OverflowError, SyntaxError):
577 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000578 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000579 print('*** Error in script or command!\n', file=tkerr)
580 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000581 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000582 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000583 else:
584 self.runcode(code)
585
586 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000587 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000588 filename = self.stuffsource(source)
589 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000590 self.save_warnings_filters = warnings.filters[:]
591 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000592 if isinstance(source, types.UnicodeType):
593 import IOBinding
594 try:
595 source = source.encode(IOBinding.encoding)
596 except UnicodeError:
597 self.tkconsole.resetoutput()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000598 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000599 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000600 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000601 # InteractiveInterpreter.runsource() calls its runcode() method,
602 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000603 return InteractiveInterpreter.runsource(self, source, filename)
604 finally:
605 if self.save_warnings_filters is not None:
606 warnings.filters[:] = self.save_warnings_filters
607 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000608
609 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000610 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000611 filename = "<pyshell#%d>" % self.gid
612 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000613 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000614 linecache.cache[filename] = len(source)+1, 0, lines, filename
615 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000616
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000617 def prepend_syspath(self, filename):
618 "Prepend sys.path with file's directory if not already included"
619 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000620 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000621 import sys as _sys
622 from os.path import dirname as _dirname
623 _dir = _dirname(_filename)
624 if not _dir in _sys.path:
625 _sys.path.insert(0, _dir)
626 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000627 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000628
David Scherer7aced172000-08-15 01:13:23 +0000629 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000630 """Extend base class method: Add Colorizing
631
632 Color the offending position instead of printing it and pointing at it
633 with a caret.
634
635 """
David Scherer7aced172000-08-15 01:13:23 +0000636 text = self.tkconsole.text
637 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000638 if stuff:
639 msg, lineno, offset, line = stuff
640 if lineno == 1:
641 pos = "iomark + %d chars" % (offset-1)
642 else:
643 pos = "iomark linestart + %d lines + %d chars" % \
644 (lineno-1, offset-1)
645 text.tag_add("ERROR", pos)
646 text.see(pos)
647 char = text.get(pos)
648 if char and char in IDENTCHARS:
649 text.tag_add("ERROR", pos + " wordstart", pos)
650 self.tkconsole.resetoutput()
651 self.write("SyntaxError: %s\n" % str(msg))
652 else:
David Scherer7aced172000-08-15 01:13:23 +0000653 self.tkconsole.resetoutput()
654 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000655 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000656
657 def unpackerror(self):
658 type, value, tb = sys.exc_info()
659 ok = type is SyntaxError
660 if ok:
661 try:
662 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000663 if not offset:
664 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000665 except:
666 ok = 0
667 if ok:
668 return msg, lineno, offset, line
669 else:
670 return None
671
672 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000673 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000674 self.tkconsole.resetoutput()
675 self.checklinecache()
676 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000677 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
678 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000679
680 def checklinecache(self):
681 c = linecache.cache
682 for key in c.keys():
683 if key[:1] + key[-1:] != "<>":
684 del c[key]
685
Chui Tey5d2af632002-05-26 13:36:41 +0000686 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000687 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000688 # The code better not raise an exception!
689 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000690 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000691 return 0
692 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000693 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000694 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000695 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000696 return 1
697
David Scherer7aced172000-08-15 01:13:23 +0000698 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000699 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000700 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000701 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000702 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000703 if self.save_warnings_filters is not None:
704 warnings.filters[:] = self.save_warnings_filters
705 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000706 debugger = self.debugger
707 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000708 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000709 if not debugger and self.rpcclt is not None:
710 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
711 (code,), {})
712 elif debugger:
713 debugger.run(code, self.locals)
714 else:
715 exec(code, self.locals)
716 except SystemExit:
717 if not self.tkconsole.closing:
718 if tkMessageBox.askyesno(
719 "Exit?",
720 "Do you want to exit altogether?",
721 default="yes",
722 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000723 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000724 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000725 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000726 else:
727 raise
728 except:
729 if use_subprocess:
730 print("IDLE internal error in runcode()",
731 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000732 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000733 self.tkconsole.endexecuting()
734 else:
735 if self.tkconsole.canceled:
736 self.tkconsole.canceled = False
737 print("KeyboardInterrupt", file=self.tkconsole.stderr)
738 else:
739 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000740 finally:
741 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000742 try:
743 self.tkconsole.endexecuting()
744 except AttributeError: # shell may have closed
745 pass
David Scherer7aced172000-08-15 01:13:23 +0000746
747 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000748 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000749 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000750
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000751 def display_port_binding_error(self):
752 tkMessageBox.showerror(
753 "Port Binding Error",
754 "IDLE can't bind TCP/IP port 8833, which is necessary to "
755 "communicate with its Python execution server. Either "
756 "no networking is installed on this computer or another "
757 "process (another IDLE?) is using the port. Run IDLE with the -n "
758 "command line switch to start without a subprocess and refer to "
759 "Help/IDLE Help 'Running without a subprocess' for further "
760 "details.",
761 master=self.tkconsole.text)
762
763 def display_no_subprocess_error(self):
764 tkMessageBox.showerror(
765 "Subprocess Startup Error",
766 "IDLE's subprocess didn't make connection. Either IDLE can't "
767 "start a subprocess or personal firewall software is blocking "
768 "the connection.",
769 master=self.tkconsole.text)
770
771 def display_executing_dialog(self):
772 tkMessageBox.showerror(
773 "Already executing",
774 "The Python Shell window is already executing a command; "
775 "please wait until it is finished.",
776 master=self.tkconsole.text)
777
778
David Scherer7aced172000-08-15 01:13:23 +0000779class PyShell(OutputWindow):
780
781 shell_title = "Python Shell"
782
783 # Override classes
784 ColorDelegator = ModifiedColorDelegator
785 UndoDelegator = ModifiedUndoDelegator
786
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000787 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000788 menu_specs = [
789 ("file", "_File"),
790 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000791 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000792 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000793 ("windows", "_Windows"),
794 ("help", "_Help"),
795 ]
David Scherer7aced172000-08-15 01:13:23 +0000796
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000797 if macosxSupport.runningAsOSXApp():
798 del menu_specs[-3]
799 menu_specs[-2] = ("windows", "_Window")
800
801
David Scherer7aced172000-08-15 01:13:23 +0000802 # New classes
803 from IdleHistory import History
804
805 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000806 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000807 ms = self.menu_specs
808 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000809 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000810 self.interp = ModifiedInterpreter(self)
811 if flist is None:
812 root = Tk()
813 fixwordbreaks(root)
814 root.withdraw()
815 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000816 #
David Scherer7aced172000-08-15 01:13:23 +0000817 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000818 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000819## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
820 self.usetabs = True
821 # indentwidth must be 8 when using tabs. See note in EditorWindow:
822 self.indentwidth = 8
823 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000824 #
David Scherer7aced172000-08-15 01:13:23 +0000825 text = self.text
826 text.configure(wrap="char")
827 text.bind("<<newline-and-indent>>", self.enter_callback)
828 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
829 text.bind("<<interrupt-execution>>", self.cancel_callback)
830 text.bind("<<beginning-of-line>>", self.home_callback)
831 text.bind("<<end-of-file>>", self.eof_callback)
832 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000833 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000834 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000835 if use_subprocess:
836 text.bind("<<view-restart>>", self.view_restart_mark)
837 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000838 #
David Scherer7aced172000-08-15 01:13:23 +0000839 self.save_stdout = sys.stdout
840 self.save_stderr = sys.stderr
841 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000842 import IOBinding
843 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
844 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
845 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000846 if not use_subprocess:
847 sys.stdout = self.stdout
848 sys.stderr = self.stderr
849 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000850 #
David Scherer7aced172000-08-15 01:13:23 +0000851 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000852 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000853 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000854
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000855 def get_standard_extension_names(self):
856 return idleConf.GetExtensions(shell_only=True)
857
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000858 reading = False
859 executing = False
860 canceled = False
861 endoffile = False
862 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000863
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000864 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000865 global warning_stream
866 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000867
868 def get_warning_stream(self):
869 return warning_stream
870
David Scherer7aced172000-08-15 01:13:23 +0000871 def toggle_debugger(self, event=None):
872 if self.executing:
873 tkMessageBox.showerror("Don't debug now",
874 "You can only toggle the debugger when idle",
875 master=self.text)
876 self.set_debugger_indicator()
877 return "break"
878 else:
879 db = self.interp.getdebugger()
880 if db:
881 self.close_debugger()
882 else:
883 self.open_debugger()
884
885 def set_debugger_indicator(self):
886 db = self.interp.getdebugger()
887 self.setvar("<<toggle-debugger>>", not not db)
888
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000889 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000890 pass # All we need is the variable
891
892 def close_debugger(self):
893 db = self.interp.getdebugger()
894 if db:
895 self.interp.setdebugger(None)
896 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000897 if self.interp.rpcclt:
898 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000899 self.resetoutput()
900 self.console.write("[DEBUG OFF]\n")
901 sys.ps1 = ">>> "
902 self.showprompt()
903 self.set_debugger_indicator()
904
905 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000906 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000907 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
908 self)
909 else:
910 dbg_gui = Debugger.Debugger(self)
911 self.interp.setdebugger(dbg_gui)
912 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000913 sys.ps1 = "[DEBUG ON]\n>>> "
914 self.showprompt()
915 self.set_debugger_indicator()
916
David Scherer7aced172000-08-15 01:13:23 +0000917 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000918 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000919 self.resetoutput()
920 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000921
922 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000923 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000924 self.executing = 0
925 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000926 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000927
928 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000929 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000930 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000931 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000932 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000933 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000934 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000935 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000936 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000937 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000938 if self.reading:
939 self.top.quit()
940 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000941 self.closing = True
942 # Wait for poll_subprocess() rescheduling to stop
943 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000944
945 def close2(self):
946 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000947
948 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000949 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000950 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000951 if use_subprocess:
952 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000953 # Restore std streams
954 sys.stdout = self.save_stdout
955 sys.stderr = self.save_stderr
956 sys.stdin = self.save_stdin
957 # Break cycles
958 self.interp = None
959 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000960 self.flist.pyshell = None
961 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000962 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000963
964 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000965 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000966 return True
David Scherer7aced172000-08-15 01:13:23 +0000967
968 def short_title(self):
969 return self.shell_title
970
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000971 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000972 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000973
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000974 firewallmessage = """
975 ****************************************************************
976 Personal firewall software may warn about the connection IDLE
977 makes to its subprocess using this computer's internal loopback
978 interface. This connection is not visible on any external
979 interface and no data is sent to or received from the Internet.
980 ****************************************************************
981 """
982
David Scherer7aced172000-08-15 01:13:23 +0000983 def begin(self):
984 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000985 if use_subprocess:
986 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000987 client = self.interp.start_subprocess()
988 if not client:
989 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000990 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000991 else:
992 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000993 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000994 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000995 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000996 self.showprompt()
997 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000998 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000999 return True
David Scherer7aced172000-08-15 01:13:23 +00001000
1001 def readline(self):
1002 save = self.reading
1003 try:
1004 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001005 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001006 finally:
1007 self.reading = save
1008 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001009 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1010 line = "\n"
Guido van Rossumef87d6e2007-05-02 19:09:54 +00001011 if isinstance(line, str):
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001012 import IOBinding
1013 try:
1014 line = line.encode(IOBinding.encoding)
1015 except UnicodeError:
1016 pass
David Scherer7aced172000-08-15 01:13:23 +00001017 self.resetoutput()
1018 if self.canceled:
1019 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001020 if not use_subprocess:
1021 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001022 if self.endoffile:
1023 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001024 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001025 return line
1026
1027 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001028 return True
David Scherer7aced172000-08-15 01:13:23 +00001029
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001030 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001031 try:
1032 if self.text.compare("sel.first", "!=", "sel.last"):
1033 return # Active selection -- always use default binding
1034 except:
1035 pass
1036 if not (self.executing or self.reading):
1037 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001038 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001039 self.showprompt()
1040 return "break"
1041 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001042 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001043 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001044 if self.interp.getdebugger():
1045 self.interp.restart_subprocess()
1046 else:
1047 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001048 if self.reading:
1049 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001050 return "break"
1051
1052 def eof_callback(self, event):
1053 if self.executing and not self.reading:
1054 return # Let the default binding (delete next char) take over
1055 if not (self.text.compare("iomark", "==", "insert") and
1056 self.text.compare("insert", "==", "end-1c")):
1057 return # Let the default binding (delete next char) take over
1058 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001059 self.resetoutput()
1060 self.close()
1061 else:
1062 self.canceled = 0
1063 self.endoffile = 1
1064 self.top.quit()
1065 return "break"
1066
1067 def home_callback(self, event):
1068 if event.state != 0 and event.keysym == "Home":
1069 return # <Modifier-Home>; fall back to class binding
1070 if self.text.compare("iomark", "<=", "insert") and \
1071 self.text.compare("insert linestart", "<=", "iomark"):
1072 self.text.mark_set("insert", "iomark")
1073 self.text.tag_remove("sel", "1.0", "end")
1074 self.text.see("insert")
1075 return "break"
1076
1077 def linefeed_callback(self, event):
1078 # Insert a linefeed without entering anything (still autoindented)
1079 if self.reading:
1080 self.text.insert("insert", "\n")
1081 self.text.see("insert")
1082 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001083 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001084 return "break"
1085
1086 def enter_callback(self, event):
1087 if self.executing and not self.reading:
1088 return # Let the default binding (insert '\n') take over
1089 # If some text is selected, recall the selection
1090 # (but only if this before the I/O mark)
1091 try:
1092 sel = self.text.get("sel.first", "sel.last")
1093 if sel:
1094 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001095 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001096 return "break"
1097 except:
1098 pass
1099 # If we're strictly before the line containing iomark, recall
1100 # the current line, less a leading prompt, less leading or
1101 # trailing whitespace
1102 if self.text.compare("insert", "<", "iomark linestart"):
1103 # Check if there's a relevant stdin range -- if so, use it
1104 prev = self.text.tag_prevrange("stdin", "insert")
1105 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001106 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001107 return "break"
1108 next = self.text.tag_nextrange("stdin", "insert")
1109 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001110 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001111 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001112 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001113 indices = self.text.tag_nextrange("console", "insert linestart")
1114 if indices and \
1115 self.text.compare(indices[0], "<=", "insert linestart"):
1116 self.recall(self.text.get(indices[1], "insert lineend"), event)
1117 else:
1118 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001119 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001120 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001121 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001122 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001123 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001124 # If we're in the current input and there's only whitespace
1125 # beyond the cursor, erase that whitespace first
1126 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001127 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001128 self.text.delete("insert", "end-1c")
1129 # If we're in the current input before its last line,
1130 # insert a newline right at the insert point
1131 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001132 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001133 return "break"
1134 # We're in the last line; append a newline and submit it
1135 self.text.mark_set("insert", "end-1c")
1136 if self.reading:
1137 self.text.insert("insert", "\n")
1138 self.text.see("insert")
1139 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001140 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001141 self.text.tag_add("stdin", "iomark", "end-1c")
1142 self.text.update_idletasks()
1143 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001144 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001145 else:
1146 self.runit()
1147 return "break"
1148
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001149 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001150 # remove leading and trailing empty or whitespace lines
1151 s = re.sub(r'^\s*\n', '' , s)
1152 s = re.sub(r'\n\s*$', '', s)
1153 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001154 self.text.undo_block_start()
1155 try:
1156 self.text.tag_remove("sel", "1.0", "end")
1157 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001158 prefix = self.text.get("insert linestart", "insert")
1159 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001160 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001161 prefix = self.text.get("insert linestart", "insert")
1162 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001163 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001164 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1165 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001166 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001167 if line.startswith(orig_base_indent):
1168 # replace orig base indentation with new indentation
1169 line = new_base_indent + line[len(orig_base_indent):]
1170 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001171 finally:
1172 self.text.see("insert")
1173 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001174
1175 def runit(self):
1176 line = self.text.get("iomark", "end-1c")
1177 # Strip off last newline and surrounding whitespace.
1178 # (To allow you to hit return twice to end a statement.)
1179 i = len(line)
1180 while i > 0 and line[i-1] in " \t":
1181 i = i-1
1182 if i > 0 and line[i-1] == "\n":
1183 i = i-1
1184 while i > 0 and line[i-1] in " \t":
1185 i = i-1
1186 line = line[:i]
1187 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001188
David Scherer7aced172000-08-15 01:13:23 +00001189 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001190 if self.interp.rpcclt:
1191 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001192 try:
1193 sys.last_traceback
1194 except:
1195 tkMessageBox.showerror("No stack trace",
1196 "There is no stack trace yet.\n"
1197 "(sys.last_traceback is not defined)",
1198 master=self.text)
1199 return
1200 from StackViewer import StackBrowser
1201 sv = StackBrowser(self.root, self.flist)
1202
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001203 def view_restart_mark(self, event=None):
1204 self.text.see("iomark")
1205 self.text.see("restart")
1206
1207 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001208 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001209
David Scherer7aced172000-08-15 01:13:23 +00001210 def showprompt(self):
1211 self.resetoutput()
1212 try:
1213 s = str(sys.ps1)
1214 except:
1215 s = ""
1216 self.console.write(s)
1217 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001218 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001219 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001220
1221 def resetoutput(self):
1222 source = self.text.get("iomark", "end-1c")
1223 if self.history:
1224 self.history.history_store(source)
1225 if self.text.get("end-2c") != "\n":
1226 self.text.insert("end-1c", "\n")
1227 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001228 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001229
1230 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001231 try:
1232 self.text.mark_gravity("iomark", "right")
1233 OutputWindow.write(self, s, tags, "iomark")
1234 self.text.mark_gravity("iomark", "left")
1235 except:
1236 pass
David Scherer7aced172000-08-15 01:13:23 +00001237 if self.canceled:
1238 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001239 if not use_subprocess:
1240 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001241
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001242class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001243
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001244 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001245 self.shell = shell
1246 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001247 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001248
1249 def write(self, s):
1250 self.shell.write(s, self.tags)
1251
1252 def writelines(self, l):
1253 map(self.write, l)
1254
1255 def flush(self):
1256 pass
1257
1258 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001259 return True
David Scherer7aced172000-08-15 01:13:23 +00001260
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001261
David Scherer7aced172000-08-15 01:13:23 +00001262usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001263
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001264USAGE: idle [-deins] [-t title] [file]*
1265 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1266 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001267
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001268 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001269 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001270
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001271The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001272
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001273 -e open an edit window
1274 -i open a shell window
1275
1276The following options imply -i and will open a shell:
1277
1278 -c cmd run the command in a shell, or
1279 -r file run script from file
1280
1281 -d enable the debugger
1282 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1283 -t title set title of shell window
1284
1285A default edit window will be bypassed when -c, -r, or - are used.
1286
1287[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1288
1289Examples:
1290
1291idle
1292 Open an edit window or shell depending on IDLE's configuration.
1293
1294idle foo.py foobar.py
1295 Edit the files, also open a shell if configured to start with shell.
1296
1297idle -est "Baz" foo.py
1298 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1299 window with the title "Baz".
1300
1301idle -c "import sys; print sys.argv" "foo"
1302 Open a shell window and run the command, passing "-c" in sys.argv[0]
1303 and "foo" in sys.argv[1].
1304
1305idle -d -s -r foo.py "Hello World"
1306 Open a shell window, run a startup script, enable the debugger, and
1307 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1308 sys.argv[1].
1309
1310echo "import sys; print sys.argv" | idle - "foobar"
1311 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1312 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001313"""
1314
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001315def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001316 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001317
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001318 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001319 enable_shell = False
1320 enable_edit = False
1321 debug = False
1322 cmd = None
1323 script = None
1324 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001325 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001326 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001327 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001328 sys.stderr.write("Error: %s\n" % str(msg))
1329 sys.stderr.write(usage_msg)
1330 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001331 for o, a in opts:
1332 if o == '-c':
1333 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001334 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001335 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001336 debug = True
1337 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001338 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001339 enable_edit = True
1340 if o == '-h':
1341 sys.stdout.write(usage_msg)
1342 sys.exit()
1343 if o == '-i':
1344 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001345 if o == '-n':
1346 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001347 if o == '-r':
1348 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001349 if os.path.isfile(script):
1350 pass
1351 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001352 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001353 sys.exit()
1354 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001355 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001356 startup = True
1357 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001358 if o == '-t':
1359 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001360 enable_shell = True
1361 if args and args[0] == '-':
1362 cmd = sys.stdin.read()
1363 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001365 for i in range(len(sys.path)):
1366 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001367 if args and args[0] == '-':
1368 sys.argv = [''] + args[1:]
1369 elif cmd:
1370 sys.argv = ['-c'] + args
1371 elif script:
1372 sys.argv = [script] + args
1373 elif args:
1374 enable_edit = True
1375 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001376 for filename in args:
1377 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001378 for dir in pathx:
1379 dir = os.path.abspath(dir)
1380 if not dir in sys.path:
1381 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001382 else:
1383 dir = os.getcwd()
1384 if not dir in sys.path:
1385 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001386 # check the IDLE settings configuration (but command line overrides)
1387 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001388 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001389 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001390 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001391 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001392 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001393
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001394 fixwordbreaks(root)
1395 root.withdraw()
1396 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001397 macosxSupport.setupApp(root, flist)
1398
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001399 if enable_edit:
1400 if not (cmd or script):
1401 for filename in args:
1402 flist.open(filename)
1403 if not args:
1404 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001405 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001406 shell = flist.open_shell()
1407 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001408 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001409
1410 if macosxSupport.runningAsOSXApp() and flist.dict:
1411 # On OSX: when the user has double-clicked on a file that causes
1412 # IDLE to be launched the shell window will open just in front of
1413 # the file she wants to see. Lower the interpreter window when
1414 # there are open files.
1415 shell.top.lower()
1416
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001417 shell = flist.pyshell
1418 # handle remaining options:
1419 if debug:
1420 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001421 if startup:
1422 filename = os.environ.get("IDLESTARTUP") or \
1423 os.environ.get("PYTHONSTARTUP")
1424 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001425 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001426 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001427 shell.interp.runcommand("""if 1:
1428 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001429 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001430 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001431 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001432 if cmd:
1433 shell.interp.execsource(cmd)
1434 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001435 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001436 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001437
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001438 root.mainloop()
1439 root.destroy()
1440
David Scherer7aced172000-08-15 01:13:23 +00001441if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001442 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001443 main()