blob: f11e609d9ce75e585696e8f1aeaca65851234eb2 [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]
354 # Maybe IDLE is installed and is being accessed via sys.path,
355 # or maybe it's not installed and the idle.py script is being
356 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000357 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
358 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000359 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000360 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000361 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000362 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000363 if sys.platform[:3] == 'win' and ' ' in sys.executable:
364 # handle embedded space in path by quoting the argument
365 decorated_exec = '"%s"' % sys.executable
366 else:
367 decorated_exec = sys.executable
368 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000369
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000370 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000371 # spawning first avoids passing a listening socket to the subprocess
372 self.spawn_subprocess()
373 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000374 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000375 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000376 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000377 time.sleep(i)
378 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000379 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000380 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000381 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000382 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000383 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000384 self.display_port_binding_error()
385 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000386 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000387 self.rpcclt.listening_sock.settimeout(10)
388 try:
389 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000390 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000391 self.display_no_subprocess_error()
392 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000393 self.rpcclt.register("stdin", self.tkconsole)
394 self.rpcclt.register("stdout", self.tkconsole.stdout)
395 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000396 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000397 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000398 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000399 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000400 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000401 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000402
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000403 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000404 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000405 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000406 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000407 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000408 debug = self.getdebugger()
409 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000410 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000411 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000412 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
413 except:
414 pass
415 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000416 self.rpcclt.close()
417 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000418 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000419 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000420 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000421 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000422 try:
423 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000424 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000425 self.display_no_subprocess_error()
426 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000427 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000428 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000429 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000430 if was_executing:
431 console.write('\n')
432 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000433 halfbar = ((int(console.width) - 16) // 2) * '='
434 console.write(halfbar + ' RESTART ' + halfbar)
435 console.text.mark_set("restart", "end-1c")
436 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000437 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000438 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000439 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000440 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000441 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000442 # reload remote debugger breakpoints for all PyShellEditWindows
443 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000444 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000445 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000446
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000447 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000448 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000449
450 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000451 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000453 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000454 try:
455 self.rpcclt.close()
456 except AttributeError: # no socket
457 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000458 self.unix_terminate()
459 self.tkconsole.executing = False
460 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000461
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000462 def unix_terminate(self):
463 "UNIX: make sure subprocess is terminated and collect status"
464 if hasattr(os, 'kill'):
465 try:
466 os.kill(self.rpcpid, SIGTERM)
467 except OSError:
468 # process already terminated:
469 return
470 else:
471 try:
472 os.waitpid(self.rpcpid, 0)
473 except OSError:
474 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000475
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000476 def transfer_path(self):
477 self.runcommand("""if 1:
478 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000479 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000480 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000481 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000482
Chui Tey5d2af632002-05-26 13:36:41 +0000483 active_seq = None
484
485 def poll_subprocess(self):
486 clt = self.rpcclt
487 if clt is None:
488 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000489 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000490 response = clt.pollresponse(self.active_seq, wait=0.05)
491 except (EOFError, IOError, KeyboardInterrupt):
492 # lost connection or subprocess terminated itself, restart
493 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000494 if self.tkconsole.closing:
495 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000496 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000497 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000498 if response:
499 self.tkconsole.resetoutput()
500 self.active_seq = None
501 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000502 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000503 if how == "OK":
504 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000505 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000506 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000507 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
508 self.remote_stack_viewer()
509 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000510 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000511 print(errmsg, what, file=sys.__stderr__)
512 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000513 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000514 try:
515 self.tkconsole.endexecuting()
516 except AttributeError: # shell may have closed
517 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000518 # Reschedule myself
519 if not self.tkconsole.closing:
520 self.tkconsole.text.after(self.tkconsole.pollinterval,
521 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000522
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000523 debugger = None
524
525 def setdebugger(self, debugger):
526 self.debugger = debugger
527
528 def getdebugger(self):
529 return self.debugger
530
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000531 def open_remote_stack_viewer(self):
532 """Initiate the remote stack viewer from a separate thread.
533
534 This method is called from the subprocess, and by returning from this
535 method we allow the subprocess to unblock. After a bit the shell
536 requests the subprocess to open the remote stack viewer which returns a
537 static object looking at the last exceptiopn. It is queried through
538 the RPC mechanism.
539
540 """
541 self.tkconsole.text.after(300, self.remote_stack_viewer)
542 return
543
Chui Tey5d2af632002-05-26 13:36:41 +0000544 def remote_stack_viewer(self):
545 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000546 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000547 if oid is None:
548 self.tkconsole.root.bell()
549 return
550 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
551 from TreeWidget import ScrolledCanvas, TreeNode
552 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000553 theme = idleConf.GetOption('main','Theme','name')
554 background = idleConf.GetHighlight(theme, 'normal')['background']
555 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000556 sc.frame.pack(expand=1, fill="both")
557 node = TreeNode(sc.canvas, None, item)
558 node.expand()
559 # XXX Should GC the remote tree when closing the window
560
David Scherer7aced172000-08-15 01:13:23 +0000561 gid = 0
562
563 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000564 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000565 filename = self.stuffsource(source)
566 self.execfile(filename, source)
567
568 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000569 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000570 if source is None:
571 source = open(filename, "r").read()
572 try:
573 code = compile(source, filename, "exec")
574 except (OverflowError, SyntaxError):
575 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000576 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000577 print('*** Error in script or command!\n', file=tkerr)
578 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000579 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000580 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000581 else:
582 self.runcode(code)
583
584 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000585 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000586 filename = self.stuffsource(source)
587 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000588 self.save_warnings_filters = warnings.filters[:]
589 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000590 if isinstance(source, types.UnicodeType):
591 import IOBinding
592 try:
593 source = source.encode(IOBinding.encoding)
594 except UnicodeError:
595 self.tkconsole.resetoutput()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000596 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000597 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000598 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000599 # InteractiveInterpreter.runsource() calls its runcode() method,
600 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000601 return InteractiveInterpreter.runsource(self, source, filename)
602 finally:
603 if self.save_warnings_filters is not None:
604 warnings.filters[:] = self.save_warnings_filters
605 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000606
607 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000608 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000609 filename = "<pyshell#%d>" % self.gid
610 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000611 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000612 linecache.cache[filename] = len(source)+1, 0, lines, filename
613 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000614
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000615 def prepend_syspath(self, filename):
616 "Prepend sys.path with file's directory if not already included"
617 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000618 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000619 import sys as _sys
620 from os.path import dirname as _dirname
621 _dir = _dirname(_filename)
622 if not _dir in _sys.path:
623 _sys.path.insert(0, _dir)
624 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000625 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000626
David Scherer7aced172000-08-15 01:13:23 +0000627 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000628 """Extend base class method: Add Colorizing
629
630 Color the offending position instead of printing it and pointing at it
631 with a caret.
632
633 """
David Scherer7aced172000-08-15 01:13:23 +0000634 text = self.tkconsole.text
635 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000636 if stuff:
637 msg, lineno, offset, line = stuff
638 if lineno == 1:
639 pos = "iomark + %d chars" % (offset-1)
640 else:
641 pos = "iomark linestart + %d lines + %d chars" % \
642 (lineno-1, offset-1)
643 text.tag_add("ERROR", pos)
644 text.see(pos)
645 char = text.get(pos)
646 if char and char in IDENTCHARS:
647 text.tag_add("ERROR", pos + " wordstart", pos)
648 self.tkconsole.resetoutput()
649 self.write("SyntaxError: %s\n" % str(msg))
650 else:
David Scherer7aced172000-08-15 01:13:23 +0000651 self.tkconsole.resetoutput()
652 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000653 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000654
655 def unpackerror(self):
656 type, value, tb = sys.exc_info()
657 ok = type is SyntaxError
658 if ok:
659 try:
660 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000661 if not offset:
662 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000663 except:
664 ok = 0
665 if ok:
666 return msg, lineno, offset, line
667 else:
668 return None
669
670 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000671 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000672 self.tkconsole.resetoutput()
673 self.checklinecache()
674 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000675 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
676 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000677
678 def checklinecache(self):
679 c = linecache.cache
680 for key in c.keys():
681 if key[:1] + key[-1:] != "<>":
682 del c[key]
683
Chui Tey5d2af632002-05-26 13:36:41 +0000684 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000685 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000686 # The code better not raise an exception!
687 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000688 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000689 return 0
690 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000691 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000692 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000693 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000694 return 1
695
David Scherer7aced172000-08-15 01:13:23 +0000696 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000697 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000698 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000699 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000700 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000701 if self.save_warnings_filters is not None:
702 warnings.filters[:] = self.save_warnings_filters
703 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000704 debugger = self.debugger
705 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000706 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000707 if not debugger and self.rpcclt is not None:
708 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
709 (code,), {})
710 elif debugger:
711 debugger.run(code, self.locals)
712 else:
713 exec(code, self.locals)
714 except SystemExit:
715 if not self.tkconsole.closing:
716 if tkMessageBox.askyesno(
717 "Exit?",
718 "Do you want to exit altogether?",
719 default="yes",
720 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000721 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000722 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000723 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000724 else:
725 raise
726 except:
727 if use_subprocess:
728 print("IDLE internal error in runcode()",
729 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000730 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000731 self.tkconsole.endexecuting()
732 else:
733 if self.tkconsole.canceled:
734 self.tkconsole.canceled = False
735 print("KeyboardInterrupt", file=self.tkconsole.stderr)
736 else:
737 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000738 finally:
739 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000740 try:
741 self.tkconsole.endexecuting()
742 except AttributeError: # shell may have closed
743 pass
David Scherer7aced172000-08-15 01:13:23 +0000744
745 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000746 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000747 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000748
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000749 def display_port_binding_error(self):
750 tkMessageBox.showerror(
751 "Port Binding Error",
752 "IDLE can't bind TCP/IP port 8833, which is necessary to "
753 "communicate with its Python execution server. Either "
754 "no networking is installed on this computer or another "
755 "process (another IDLE?) is using the port. Run IDLE with the -n "
756 "command line switch to start without a subprocess and refer to "
757 "Help/IDLE Help 'Running without a subprocess' for further "
758 "details.",
759 master=self.tkconsole.text)
760
761 def display_no_subprocess_error(self):
762 tkMessageBox.showerror(
763 "Subprocess Startup Error",
764 "IDLE's subprocess didn't make connection. Either IDLE can't "
765 "start a subprocess or personal firewall software is blocking "
766 "the connection.",
767 master=self.tkconsole.text)
768
769 def display_executing_dialog(self):
770 tkMessageBox.showerror(
771 "Already executing",
772 "The Python Shell window is already executing a command; "
773 "please wait until it is finished.",
774 master=self.tkconsole.text)
775
776
David Scherer7aced172000-08-15 01:13:23 +0000777class PyShell(OutputWindow):
778
779 shell_title = "Python Shell"
780
781 # Override classes
782 ColorDelegator = ModifiedColorDelegator
783 UndoDelegator = ModifiedUndoDelegator
784
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000785 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000786 menu_specs = [
787 ("file", "_File"),
788 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000789 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000790 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000791 ("windows", "_Windows"),
792 ("help", "_Help"),
793 ]
David Scherer7aced172000-08-15 01:13:23 +0000794
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000795 if macosxSupport.runningAsOSXApp():
796 del menu_specs[-3]
797 menu_specs[-2] = ("windows", "_Window")
798
799
David Scherer7aced172000-08-15 01:13:23 +0000800 # New classes
801 from IdleHistory import History
802
803 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000804 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000805 ms = self.menu_specs
806 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000807 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000808 self.interp = ModifiedInterpreter(self)
809 if flist is None:
810 root = Tk()
811 fixwordbreaks(root)
812 root.withdraw()
813 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000814 #
David Scherer7aced172000-08-15 01:13:23 +0000815 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000816 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000817## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
818 self.usetabs = True
819 # indentwidth must be 8 when using tabs. See note in EditorWindow:
820 self.indentwidth = 8
821 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000822 #
David Scherer7aced172000-08-15 01:13:23 +0000823 text = self.text
824 text.configure(wrap="char")
825 text.bind("<<newline-and-indent>>", self.enter_callback)
826 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
827 text.bind("<<interrupt-execution>>", self.cancel_callback)
828 text.bind("<<beginning-of-line>>", self.home_callback)
829 text.bind("<<end-of-file>>", self.eof_callback)
830 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000831 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000832 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000833 if use_subprocess:
834 text.bind("<<view-restart>>", self.view_restart_mark)
835 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000836 #
David Scherer7aced172000-08-15 01:13:23 +0000837 self.save_stdout = sys.stdout
838 self.save_stderr = sys.stderr
839 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000840 import IOBinding
841 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
842 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
843 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000844 if not use_subprocess:
845 sys.stdout = self.stdout
846 sys.stderr = self.stderr
847 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000848 #
David Scherer7aced172000-08-15 01:13:23 +0000849 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000850 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000851 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000852
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000853 def get_standard_extension_names(self):
854 return idleConf.GetExtensions(shell_only=True)
855
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000856 reading = False
857 executing = False
858 canceled = False
859 endoffile = False
860 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000861
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000862 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000863 global warning_stream
864 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000865
866 def get_warning_stream(self):
867 return warning_stream
868
David Scherer7aced172000-08-15 01:13:23 +0000869 def toggle_debugger(self, event=None):
870 if self.executing:
871 tkMessageBox.showerror("Don't debug now",
872 "You can only toggle the debugger when idle",
873 master=self.text)
874 self.set_debugger_indicator()
875 return "break"
876 else:
877 db = self.interp.getdebugger()
878 if db:
879 self.close_debugger()
880 else:
881 self.open_debugger()
882
883 def set_debugger_indicator(self):
884 db = self.interp.getdebugger()
885 self.setvar("<<toggle-debugger>>", not not db)
886
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000887 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000888 pass # All we need is the variable
889
890 def close_debugger(self):
891 db = self.interp.getdebugger()
892 if db:
893 self.interp.setdebugger(None)
894 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000895 if self.interp.rpcclt:
896 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000897 self.resetoutput()
898 self.console.write("[DEBUG OFF]\n")
899 sys.ps1 = ">>> "
900 self.showprompt()
901 self.set_debugger_indicator()
902
903 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000904 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000905 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
906 self)
907 else:
908 dbg_gui = Debugger.Debugger(self)
909 self.interp.setdebugger(dbg_gui)
910 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000911 sys.ps1 = "[DEBUG ON]\n>>> "
912 self.showprompt()
913 self.set_debugger_indicator()
914
David Scherer7aced172000-08-15 01:13:23 +0000915 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000916 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000917 self.resetoutput()
918 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000919
920 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000921 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000922 self.executing = 0
923 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000924 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000925
926 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000927 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000928 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000929 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000930 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000931 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000932 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000933 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000934 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000935 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000936 if self.reading:
937 self.top.quit()
938 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000939 self.closing = True
940 # Wait for poll_subprocess() rescheduling to stop
941 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000942
943 def close2(self):
944 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000945
946 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000947 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000948 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000949 if use_subprocess:
950 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000951 # Restore std streams
952 sys.stdout = self.save_stdout
953 sys.stderr = self.save_stderr
954 sys.stdin = self.save_stdin
955 # Break cycles
956 self.interp = None
957 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000958 self.flist.pyshell = None
959 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000960 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000961
962 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000963 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000964 return True
David Scherer7aced172000-08-15 01:13:23 +0000965
966 def short_title(self):
967 return self.shell_title
968
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000969 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000970 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000971
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000972 firewallmessage = """
973 ****************************************************************
974 Personal firewall software may warn about the connection IDLE
975 makes to its subprocess using this computer's internal loopback
976 interface. This connection is not visible on any external
977 interface and no data is sent to or received from the Internet.
978 ****************************************************************
979 """
980
David Scherer7aced172000-08-15 01:13:23 +0000981 def begin(self):
982 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000983 if use_subprocess:
984 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000985 client = self.interp.start_subprocess()
986 if not client:
987 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000988 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000989 else:
990 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000991 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000992 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000993 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000994 self.showprompt()
995 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000996 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000997 return True
David Scherer7aced172000-08-15 01:13:23 +0000998
999 def readline(self):
1000 save = self.reading
1001 try:
1002 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001003 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001004 finally:
1005 self.reading = save
1006 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001007 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1008 line = "\n"
Guido van Rossumef87d6e2007-05-02 19:09:54 +00001009 if isinstance(line, str):
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001010 import IOBinding
1011 try:
1012 line = line.encode(IOBinding.encoding)
1013 except UnicodeError:
1014 pass
David Scherer7aced172000-08-15 01:13:23 +00001015 self.resetoutput()
1016 if self.canceled:
1017 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001018 if not use_subprocess:
1019 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001020 if self.endoffile:
1021 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001022 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001023 return line
1024
1025 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001026 return True
David Scherer7aced172000-08-15 01:13:23 +00001027
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001028 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001029 try:
1030 if self.text.compare("sel.first", "!=", "sel.last"):
1031 return # Active selection -- always use default binding
1032 except:
1033 pass
1034 if not (self.executing or self.reading):
1035 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001036 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001037 self.showprompt()
1038 return "break"
1039 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001040 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001041 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001042 if self.interp.getdebugger():
1043 self.interp.restart_subprocess()
1044 else:
1045 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001046 if self.reading:
1047 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001048 return "break"
1049
1050 def eof_callback(self, event):
1051 if self.executing and not self.reading:
1052 return # Let the default binding (delete next char) take over
1053 if not (self.text.compare("iomark", "==", "insert") and
1054 self.text.compare("insert", "==", "end-1c")):
1055 return # Let the default binding (delete next char) take over
1056 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001057 self.resetoutput()
1058 self.close()
1059 else:
1060 self.canceled = 0
1061 self.endoffile = 1
1062 self.top.quit()
1063 return "break"
1064
1065 def home_callback(self, event):
1066 if event.state != 0 and event.keysym == "Home":
1067 return # <Modifier-Home>; fall back to class binding
1068 if self.text.compare("iomark", "<=", "insert") and \
1069 self.text.compare("insert linestart", "<=", "iomark"):
1070 self.text.mark_set("insert", "iomark")
1071 self.text.tag_remove("sel", "1.0", "end")
1072 self.text.see("insert")
1073 return "break"
1074
1075 def linefeed_callback(self, event):
1076 # Insert a linefeed without entering anything (still autoindented)
1077 if self.reading:
1078 self.text.insert("insert", "\n")
1079 self.text.see("insert")
1080 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001081 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001082 return "break"
1083
1084 def enter_callback(self, event):
1085 if self.executing and not self.reading:
1086 return # Let the default binding (insert '\n') take over
1087 # If some text is selected, recall the selection
1088 # (but only if this before the I/O mark)
1089 try:
1090 sel = self.text.get("sel.first", "sel.last")
1091 if sel:
1092 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001093 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001094 return "break"
1095 except:
1096 pass
1097 # If we're strictly before the line containing iomark, recall
1098 # the current line, less a leading prompt, less leading or
1099 # trailing whitespace
1100 if self.text.compare("insert", "<", "iomark linestart"):
1101 # Check if there's a relevant stdin range -- if so, use it
1102 prev = self.text.tag_prevrange("stdin", "insert")
1103 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001104 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001105 return "break"
1106 next = self.text.tag_nextrange("stdin", "insert")
1107 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001108 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001109 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001110 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001111 indices = self.text.tag_nextrange("console", "insert linestart")
1112 if indices and \
1113 self.text.compare(indices[0], "<=", "insert linestart"):
1114 self.recall(self.text.get(indices[1], "insert lineend"), event)
1115 else:
1116 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001117 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001118 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001119 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001120 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001121 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001122 # If we're in the current input and there's only whitespace
1123 # beyond the cursor, erase that whitespace first
1124 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001125 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001126 self.text.delete("insert", "end-1c")
1127 # If we're in the current input before its last line,
1128 # insert a newline right at the insert point
1129 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001130 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001131 return "break"
1132 # We're in the last line; append a newline and submit it
1133 self.text.mark_set("insert", "end-1c")
1134 if self.reading:
1135 self.text.insert("insert", "\n")
1136 self.text.see("insert")
1137 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001138 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001139 self.text.tag_add("stdin", "iomark", "end-1c")
1140 self.text.update_idletasks()
1141 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001142 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001143 else:
1144 self.runit()
1145 return "break"
1146
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001147 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001148 # remove leading and trailing empty or whitespace lines
1149 s = re.sub(r'^\s*\n', '' , s)
1150 s = re.sub(r'\n\s*$', '', s)
1151 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001152 self.text.undo_block_start()
1153 try:
1154 self.text.tag_remove("sel", "1.0", "end")
1155 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001156 prefix = self.text.get("insert linestart", "insert")
1157 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001158 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001159 prefix = self.text.get("insert linestart", "insert")
1160 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001161 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001162 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1163 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001164 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001165 if line.startswith(orig_base_indent):
1166 # replace orig base indentation with new indentation
1167 line = new_base_indent + line[len(orig_base_indent):]
1168 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001169 finally:
1170 self.text.see("insert")
1171 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001172
1173 def runit(self):
1174 line = self.text.get("iomark", "end-1c")
1175 # Strip off last newline and surrounding whitespace.
1176 # (To allow you to hit return twice to end a statement.)
1177 i = len(line)
1178 while i > 0 and line[i-1] in " \t":
1179 i = i-1
1180 if i > 0 and line[i-1] == "\n":
1181 i = i-1
1182 while i > 0 and line[i-1] in " \t":
1183 i = i-1
1184 line = line[:i]
1185 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001186
David Scherer7aced172000-08-15 01:13:23 +00001187 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001188 if self.interp.rpcclt:
1189 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001190 try:
1191 sys.last_traceback
1192 except:
1193 tkMessageBox.showerror("No stack trace",
1194 "There is no stack trace yet.\n"
1195 "(sys.last_traceback is not defined)",
1196 master=self.text)
1197 return
1198 from StackViewer import StackBrowser
1199 sv = StackBrowser(self.root, self.flist)
1200
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001201 def view_restart_mark(self, event=None):
1202 self.text.see("iomark")
1203 self.text.see("restart")
1204
1205 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001206 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001207
David Scherer7aced172000-08-15 01:13:23 +00001208 def showprompt(self):
1209 self.resetoutput()
1210 try:
1211 s = str(sys.ps1)
1212 except:
1213 s = ""
1214 self.console.write(s)
1215 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001216 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001217 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001218
1219 def resetoutput(self):
1220 source = self.text.get("iomark", "end-1c")
1221 if self.history:
1222 self.history.history_store(source)
1223 if self.text.get("end-2c") != "\n":
1224 self.text.insert("end-1c", "\n")
1225 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001226 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001227
1228 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001229 try:
1230 self.text.mark_gravity("iomark", "right")
1231 OutputWindow.write(self, s, tags, "iomark")
1232 self.text.mark_gravity("iomark", "left")
1233 except:
1234 pass
David Scherer7aced172000-08-15 01:13:23 +00001235 if self.canceled:
1236 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001237 if not use_subprocess:
1238 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001239
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001240class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001241
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001242 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001243 self.shell = shell
1244 self.tags = tags
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001245 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001246
1247 def write(self, s):
1248 self.shell.write(s, self.tags)
1249
1250 def writelines(self, l):
1251 map(self.write, l)
1252
1253 def flush(self):
1254 pass
1255
1256 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001257 return True
David Scherer7aced172000-08-15 01:13:23 +00001258
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001259
David Scherer7aced172000-08-15 01:13:23 +00001260usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001261
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001262USAGE: idle [-deins] [-t title] [file]*
1263 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1264 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001265
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001266 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001267 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001268
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001269The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001270
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001271 -e open an edit window
1272 -i open a shell window
1273
1274The following options imply -i and will open a shell:
1275
1276 -c cmd run the command in a shell, or
1277 -r file run script from file
1278
1279 -d enable the debugger
1280 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1281 -t title set title of shell window
1282
1283A default edit window will be bypassed when -c, -r, or - are used.
1284
1285[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1286
1287Examples:
1288
1289idle
1290 Open an edit window or shell depending on IDLE's configuration.
1291
1292idle foo.py foobar.py
1293 Edit the files, also open a shell if configured to start with shell.
1294
1295idle -est "Baz" foo.py
1296 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1297 window with the title "Baz".
1298
1299idle -c "import sys; print sys.argv" "foo"
1300 Open a shell window and run the command, passing "-c" in sys.argv[0]
1301 and "foo" in sys.argv[1].
1302
1303idle -d -s -r foo.py "Hello World"
1304 Open a shell window, run a startup script, enable the debugger, and
1305 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1306 sys.argv[1].
1307
1308echo "import sys; print sys.argv" | idle - "foobar"
1309 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1310 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001311"""
1312
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001313def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001314 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001315
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001316 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001317 enable_shell = False
1318 enable_edit = False
1319 debug = False
1320 cmd = None
1321 script = None
1322 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001323 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001324 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001325 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001326 sys.stderr.write("Error: %s\n" % str(msg))
1327 sys.stderr.write(usage_msg)
1328 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001329 for o, a in opts:
1330 if o == '-c':
1331 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001332 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001333 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001334 debug = True
1335 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001336 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001337 enable_edit = True
1338 if o == '-h':
1339 sys.stdout.write(usage_msg)
1340 sys.exit()
1341 if o == '-i':
1342 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001343 if o == '-n':
1344 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001345 if o == '-r':
1346 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001347 if os.path.isfile(script):
1348 pass
1349 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001350 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001351 sys.exit()
1352 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001353 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001354 startup = True
1355 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001356 if o == '-t':
1357 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001358 enable_shell = True
1359 if args and args[0] == '-':
1360 cmd = sys.stdin.read()
1361 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001362 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001363 for i in range(len(sys.path)):
1364 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001365 if args and args[0] == '-':
1366 sys.argv = [''] + args[1:]
1367 elif cmd:
1368 sys.argv = ['-c'] + args
1369 elif script:
1370 sys.argv = [script] + args
1371 elif args:
1372 enable_edit = True
1373 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001374 for filename in args:
1375 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001376 for dir in pathx:
1377 dir = os.path.abspath(dir)
1378 if not dir in sys.path:
1379 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001380 else:
1381 dir = os.getcwd()
1382 if not dir in sys.path:
1383 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001384 # check the IDLE settings configuration (but command line overrides)
1385 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001386 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001387 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001388 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001389 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001390 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001391
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001392 fixwordbreaks(root)
1393 root.withdraw()
1394 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001395 macosxSupport.setupApp(root, flist)
1396
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001397 if enable_edit:
1398 if not (cmd or script):
1399 for filename in args:
1400 flist.open(filename)
1401 if not args:
1402 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001403 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001404 shell = flist.open_shell()
1405 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001406 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001407
1408 if macosxSupport.runningAsOSXApp() and flist.dict:
1409 # On OSX: when the user has double-clicked on a file that causes
1410 # IDLE to be launched the shell window will open just in front of
1411 # the file she wants to see. Lower the interpreter window when
1412 # there are open files.
1413 shell.top.lower()
1414
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001415 shell = flist.pyshell
1416 # handle remaining options:
1417 if debug:
1418 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001419 if startup:
1420 filename = os.environ.get("IDLESTARTUP") or \
1421 os.environ.get("PYTHONSTARTUP")
1422 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001423 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001424 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001425 shell.interp.runcommand("""if 1:
1426 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001427 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001428 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001429 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001430 if cmd:
1431 shell.interp.execsource(cmd)
1432 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001433 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001434 shell.interp.execfile(script)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001435
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001436 root.mainloop()
1437 root.destroy()
1438
David Scherer7aced172000-08-15 01:13:23 +00001439if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001440 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001441 main()