blob: c1b98a059f4a84fe1f65a81fcbe3d0eaefe5faee [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
Ronald Oussoren19302d92006-06-11 14:33:36 +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:
Georg Brandl6634bf22008-05-20 07:13:37 +000020 from Tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000021except ImportError:
Georg Brandl6634bf22008-05-20 07:13:37 +000022 print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000023 "Your Python may not be configured for Tk. **"
24 sys.exit(1)
Georg Brandl6634bf22008-05-20 07:13:37 +000025import tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000026
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:
Benjamin Petersonb76444b2008-10-16 19:40:14 +000058 def idle_showwarning(message, category, filename, lineno,
59 file=None, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000060 file = warning_stream
61 try:
Benjamin Petersonb76444b2008-10-16 19:40:14 +000062 file.write(warnings.formatwarning(message, category, filename,\
63 lineno, file=file, line=line))
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000064 except IOError:
65 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000066 warnings.showwarning = idle_showwarning
Benjamin Petersonb76444b2008-10-16 19:40:14 +000067 def idle_formatwarning(message, category, filename, lineno,
68 file=None, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000069 """Format warnings the IDLE way"""
70 s = "\nWarning (from warnings module):\n"
71 s += ' File \"%s\", line %s\n' % (filename, lineno)
Benjamin Petersonb76444b2008-10-16 19:40:14 +000072 line = linecache.getline(filename, lineno).strip() \
73 if line is None else line
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000074 if line:
75 s += " %s\n" % line
76 s += "%s: %s\n>>> " % (category.__name__, message)
77 return s
78 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000079
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000080def extended_linecache_checkcache(filename=None,
81 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000082 """Extend linecache.checkcache to preserve the <pyshell#...> entries
83
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000084 Rather than repeating the linecache code, patch it to save the
85 <pyshell#...> entries, call the original linecache.checkcache()
86 (which destroys them), and then restore the saved entries.
87
88 orig_checkcache is bound at definition time to the original
89 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000090
91 """
David Scherer7aced172000-08-15 01:13:23 +000092 cache = linecache.cache
93 save = {}
94 for filename in cache.keys():
95 if filename[:1] + filename[-1:] == '<>':
96 save[filename] = cache[filename]
97 orig_checkcache()
98 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000099
Kurt B. Kaiser81885592002-11-29 22:10:53 +0000100# Patch linecache.checkcache():
101linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +0000102
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000103
David Scherer7aced172000-08-15 01:13:23 +0000104class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000105 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000106
David Scherer7aced172000-08-15 01:13:23 +0000107 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000108 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000109 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000110 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000111 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000112 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
113
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000114 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
115 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000116 # whenever a file is changed, restore breakpoints
117 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000118 def filename_changed_hook(old_hook=self.io.filename_change_hook,
119 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000120 self.restore_file_breaks()
121 old_hook()
122 self.io.set_filename_change_hook(filename_changed_hook)
123
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000124 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
125 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000126
Chui Teya2adb0f2002-11-04 22:14:54 +0000127 def set_breakpoint(self, lineno):
128 text = self.text
129 filename = self.io.filename
130 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
131 try:
132 i = self.breakpoints.index(lineno)
133 except ValueError: # only add if missing, i.e. do once
134 self.breakpoints.append(lineno)
135 try: # update the subprocess debugger
136 debug = self.flist.pyshell.interp.debugger
137 debug.set_breakpoint_here(filename, lineno)
138 except: # but debugger may not be active right now....
139 pass
140
David Scherer7aced172000-08-15 01:13:23 +0000141 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000142 text = self.text
143 filename = self.io.filename
144 if not filename:
145 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000146 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000147 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000148 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000149
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000150 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000151 text = self.text
152 filename = self.io.filename
153 if not filename:
154 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000155 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000156 lineno = int(float(text.index("insert")))
157 try:
158 self.breakpoints.remove(lineno)
159 except:
160 pass
161 text.tag_remove("BREAK", "insert linestart",\
162 "insert lineend +1char")
163 try:
164 debug = self.flist.pyshell.interp.debugger
165 debug.clear_breakpoint_here(filename, lineno)
166 except:
167 pass
168
169 def clear_file_breaks(self):
170 if self.breakpoints:
171 text = self.text
172 filename = self.io.filename
173 if not filename:
174 text.bell()
175 return
176 self.breakpoints = []
177 text.tag_remove("BREAK", "1.0", END)
178 try:
179 debug = self.flist.pyshell.interp.debugger
180 debug.clear_file_breaks(filename)
181 except:
182 pass
183
Chui Teya2adb0f2002-11-04 22:14:54 +0000184 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000185 "Save breakpoints when file is saved"
186 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
187 # be run. The breaks are saved at that time. If we introduce
188 # a temporary file save feature the save breaks functionality
189 # needs to be re-verified, since the breaks at the time the
190 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000191 # permanent save of the file. Currently, a break introduced
192 # after a save will be effective, but not persistent.
193 # This is necessary to keep the saved breaks synched with the
194 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000195 #
196 # Breakpoints are set as tagged ranges in the text. Certain
197 # kinds of edits cause these ranges to be deleted: Inserting
198 # or deleting a line just before a breakpoint, and certain
199 # deletions prior to a breakpoint. These issues need to be
200 # investigated and understood. It's not clear if they are
201 # Tk issues or IDLE issues, or whether they can actually
202 # be fixed. Since a modified file has to be saved before it is
203 # run, and since self.breakpoints (from which the subprocess
204 # debugger is loaded) is updated during the save, the visible
205 # breaks stay synched with the subprocess even if one of these
206 # unexpected breakpoint deletions occurs.
207 breaks = self.breakpoints
208 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000211 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000212 lines = []
213 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000214 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000215 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000216 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000217 self.update_breakpoints()
218 breaks = self.breakpoints
219 if breaks:
220 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000221 new_file.close()
222
223 def restore_file_breaks(self):
224 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225 filename = self.io.filename
226 if filename is None:
227 return
Chui Tey69371d62002-11-04 23:39:45 +0000228 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000229 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000230 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000231 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000232 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000233 for breakpoint_linenumber in breakpoint_linenumbers:
234 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000235
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000236 def update_breakpoints(self):
237 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000238 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000239 ranges = text.tag_ranges("BREAK")
240 linenumber_list = self.ranges_to_linenumbers(ranges)
241 self.breakpoints = linenumber_list
242
243 def ranges_to_linenumbers(self, ranges):
244 lines = []
245 for index in range(0, len(ranges), 2):
246 lineno = int(float(ranges[index]))
247 end = int(float(ranges[index+1]))
248 while lineno < end:
249 lines.append(lineno)
250 lineno += 1
251 return lines
252
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000253# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000254# def saved_change_hook(self):
255# "Extend base method - clear breaks if module is modified"
256# if not self.get_saved():
257# self.clear_file_breaks()
258# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000259
260 def _close(self):
261 "Extend base method - clear breaks when module is closed"
262 self.clear_file_breaks()
263 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000264
David Scherer7aced172000-08-15 01:13:23 +0000265
266class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000267 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000268
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000269 # override FileList's class variable, instances return PyShellEditorWindow
270 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000271 EditorWindow = PyShellEditorWindow
272
273 pyshell = None
274
275 def open_shell(self, event=None):
276 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000277 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000278 else:
279 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000280 if self.pyshell:
281 if not self.pyshell.begin():
282 return None
David Scherer7aced172000-08-15 01:13:23 +0000283 return self.pyshell
284
285
286class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000287 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000288
Steven M. Gavab77d3432002-03-02 07:16:21 +0000289 def __init__(self):
290 ColorDelegator.__init__(self)
291 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000292
293 def recolorize_main(self):
294 self.tag_remove("TODO", "1.0", "iomark")
295 self.tag_add("SYNC", "1.0", "iomark")
296 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000297
Steven M. Gavab77d3432002-03-02 07:16:21 +0000298 def LoadTagDefs(self):
299 ColorDelegator.LoadTagDefs(self)
300 theme = idleConf.GetOption('main','Theme','name')
301 self.tagdefs.update({
302 "stdin": {'background':None,'foreground':None},
303 "stdout": idleConf.GetHighlight(theme, "stdout"),
304 "stderr": idleConf.GetHighlight(theme, "stderr"),
305 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000306 })
David Scherer7aced172000-08-15 01:13:23 +0000307
David Scherer7aced172000-08-15 01:13:23 +0000308class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000309 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000310
311 def insert(self, index, chars, tags=None):
312 try:
313 if self.delegate.compare(index, "<", "iomark"):
314 self.delegate.bell()
315 return
316 except TclError:
317 pass
318 UndoDelegator.insert(self, index, chars, tags)
319
320 def delete(self, index1, index2=None):
321 try:
322 if self.delegate.compare(index1, "<", "iomark"):
323 self.delegate.bell()
324 return
325 except TclError:
326 pass
327 UndoDelegator.delete(self, index1, index2)
328
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000329
330class MyRPCClient(rpc.RPCClient):
331
332 def handle_EOF(self):
333 "Override the base class - just re-raise EOFError"
334 raise EOFError
335
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000336
David Scherer7aced172000-08-15 01:13:23 +0000337class ModifiedInterpreter(InteractiveInterpreter):
338
339 def __init__(self, tkconsole):
340 self.tkconsole = tkconsole
341 locals = sys.modules['__main__'].__dict__
342 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000343 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000344 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000345 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000346
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000347 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000348 rpcclt = None
349 rpcpid = None
350
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000351 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000352 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000353 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000354
Tony Lowndsf53dec22002-12-20 04:24:43 +0000355 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000356 w = ['-W' + s for s in sys.warnoptions]
Georg Brandld0761532006-10-12 07:57:21 +0000357 if 1/2 > 0: # account for new division
358 w.append('-Qnew')
Tony Lownds2398d572003-05-13 15:28:21 +0000359 # Maybe IDLE is installed and is being accessed via sys.path,
360 # or maybe it's not installed and the idle.py script is being
361 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000362 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
363 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000364 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000365 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000366 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000367 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000368 if sys.platform[:3] == 'win' and ' ' in sys.executable:
369 # handle embedded space in path by quoting the argument
370 decorated_exec = '"%s"' % sys.executable
371 else:
372 decorated_exec = sys.executable
373 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000374
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000375 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000376 # spawning first avoids passing a listening socket to the subprocess
377 self.spawn_subprocess()
378 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000379 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000380 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000381 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000382 time.sleep(i)
383 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000384 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000385 break
386 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000387 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000388 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000389 self.display_port_binding_error()
390 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000391 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000392 self.rpcclt.listening_sock.settimeout(10)
393 try:
394 self.rpcclt.accept()
395 except socket.timeout, err:
396 self.display_no_subprocess_error()
397 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000398 self.rpcclt.register("stdin", self.tkconsole)
399 self.rpcclt.register("stdout", self.tkconsole.stdout)
400 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000401 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000402 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000403 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000404 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000405 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000406 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000407
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000408 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000409 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000410 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000411 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000412 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000413 debug = self.getdebugger()
414 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000415 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000416 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000417 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
418 except:
419 pass
420 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000421 self.rpcclt.close()
422 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000423 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000424 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000425 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000426 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000427 try:
428 self.rpcclt.accept()
429 except socket.timeout, err:
430 self.display_no_subprocess_error()
431 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000432 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000433 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000434 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000435 if was_executing:
436 console.write('\n')
437 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000438 halfbar = ((int(console.width) - 16) // 2) * '='
439 console.write(halfbar + ' RESTART ' + halfbar)
440 console.text.mark_set("restart", "end-1c")
441 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000442 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000444 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000445 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000446 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000447 # reload remote debugger breakpoints for all PyShellEditWindows
448 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000449 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000450 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000451
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000452 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000453 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000454
455 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000456 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000457
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000458 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000459 try:
460 self.rpcclt.close()
461 except AttributeError: # no socket
462 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000463 self.unix_terminate()
464 self.tkconsole.executing = False
465 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000466
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000467 def unix_terminate(self):
468 "UNIX: make sure subprocess is terminated and collect status"
469 if hasattr(os, 'kill'):
470 try:
471 os.kill(self.rpcpid, SIGTERM)
472 except OSError:
473 # process already terminated:
474 return
475 else:
476 try:
477 os.waitpid(self.rpcpid, 0)
478 except OSError:
479 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000480
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000481 def transfer_path(self):
482 self.runcommand("""if 1:
483 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000484 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000485 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000486 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000487
Chui Tey5d2af632002-05-26 13:36:41 +0000488 active_seq = None
489
490 def poll_subprocess(self):
491 clt = self.rpcclt
492 if clt is None:
493 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000494 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000495 response = clt.pollresponse(self.active_seq, wait=0.05)
496 except (EOFError, IOError, KeyboardInterrupt):
497 # lost connection or subprocess terminated itself, restart
498 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000499 if self.tkconsole.closing:
500 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000501 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000502 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000503 if response:
504 self.tkconsole.resetoutput()
505 self.active_seq = None
506 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000507 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000508 if how == "OK":
509 if what is not None:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000510 print >>console, repr(what)
Chui Tey5d2af632002-05-26 13:36:41 +0000511 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000512 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
513 self.remote_stack_viewer()
514 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000515 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
516 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000517 print >>console, errmsg, what
518 # we received a response to the currently active seq number:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000519 try:
520 self.tkconsole.endexecuting()
521 except AttributeError: # shell may have closed
522 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000523 # Reschedule myself
524 if not self.tkconsole.closing:
525 self.tkconsole.text.after(self.tkconsole.pollinterval,
526 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000527
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000528 debugger = None
529
530 def setdebugger(self, debugger):
531 self.debugger = debugger
532
533 def getdebugger(self):
534 return self.debugger
535
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000536 def open_remote_stack_viewer(self):
537 """Initiate the remote stack viewer from a separate thread.
538
539 This method is called from the subprocess, and by returning from this
540 method we allow the subprocess to unblock. After a bit the shell
541 requests the subprocess to open the remote stack viewer which returns a
542 static object looking at the last exceptiopn. It is queried through
543 the RPC mechanism.
544
545 """
546 self.tkconsole.text.after(300, self.remote_stack_viewer)
547 return
548
Chui Tey5d2af632002-05-26 13:36:41 +0000549 def remote_stack_viewer(self):
550 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000551 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000552 if oid is None:
553 self.tkconsole.root.bell()
554 return
555 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
556 from TreeWidget import ScrolledCanvas, TreeNode
557 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000558 theme = idleConf.GetOption('main','Theme','name')
559 background = idleConf.GetHighlight(theme, 'normal')['background']
560 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000561 sc.frame.pack(expand=1, fill="both")
562 node = TreeNode(sc.canvas, None, item)
563 node.expand()
564 # XXX Should GC the remote tree when closing the window
565
David Scherer7aced172000-08-15 01:13:23 +0000566 gid = 0
567
568 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000569 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000570 filename = self.stuffsource(source)
571 self.execfile(filename, source)
572
573 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000574 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000575 if source is None:
576 source = open(filename, "r").read()
577 try:
578 code = compile(source, filename, "exec")
579 except (OverflowError, SyntaxError):
580 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000581 tkerr = self.tkconsole.stderr
582 print>>tkerr, '*** Error in script or command!\n'
583 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000584 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000585 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000586 else:
587 self.runcode(code)
588
589 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000590 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000591 filename = self.stuffsource(source)
592 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000593 self.save_warnings_filters = warnings.filters[:]
594 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000595 if isinstance(source, types.UnicodeType):
596 import IOBinding
597 try:
598 source = source.encode(IOBinding.encoding)
599 except UnicodeError:
600 self.tkconsole.resetoutput()
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +0000601 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000602 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000603 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000604 # InteractiveInterpreter.runsource() calls its runcode() method,
605 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000606 return InteractiveInterpreter.runsource(self, source, filename)
607 finally:
608 if self.save_warnings_filters is not None:
609 warnings.filters[:] = self.save_warnings_filters
610 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000611
612 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000613 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000614 filename = "<pyshell#%d>" % self.gid
615 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000616 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000617 linecache.cache[filename] = len(source)+1, 0, lines, filename
618 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000619
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000620 def prepend_syspath(self, filename):
621 "Prepend sys.path with file's directory if not already included"
622 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000623 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000624 import sys as _sys
625 from os.path import dirname as _dirname
626 _dir = _dirname(_filename)
627 if not _dir in _sys.path:
628 _sys.path.insert(0, _dir)
629 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000630 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000631
David Scherer7aced172000-08-15 01:13:23 +0000632 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000633 """Extend base class method: Add Colorizing
634
635 Color the offending position instead of printing it and pointing at it
636 with a caret.
637
638 """
David Scherer7aced172000-08-15 01:13:23 +0000639 text = self.tkconsole.text
640 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000641 if stuff:
642 msg, lineno, offset, line = stuff
643 if lineno == 1:
644 pos = "iomark + %d chars" % (offset-1)
645 else:
646 pos = "iomark linestart + %d lines + %d chars" % \
647 (lineno-1, offset-1)
648 text.tag_add("ERROR", pos)
649 text.see(pos)
650 char = text.get(pos)
651 if char and char in IDENTCHARS:
652 text.tag_add("ERROR", pos + " wordstart", pos)
653 self.tkconsole.resetoutput()
654 self.write("SyntaxError: %s\n" % str(msg))
655 else:
David Scherer7aced172000-08-15 01:13:23 +0000656 self.tkconsole.resetoutput()
657 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000658 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000659
660 def unpackerror(self):
661 type, value, tb = sys.exc_info()
662 ok = type is SyntaxError
663 if ok:
664 try:
665 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000666 if not offset:
667 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000668 except:
669 ok = 0
670 if ok:
671 return msg, lineno, offset, line
672 else:
673 return None
674
675 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000676 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000677 self.tkconsole.resetoutput()
678 self.checklinecache()
679 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000680 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
681 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000682
683 def checklinecache(self):
684 c = linecache.cache
685 for key in c.keys():
686 if key[:1] + key[-1:] != "<>":
687 del c[key]
688
Chui Tey5d2af632002-05-26 13:36:41 +0000689 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000690 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000691 # The code better not raise an exception!
692 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000693 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000694 return 0
695 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000696 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000697 else:
698 exec code in self.locals
699 return 1
700
David Scherer7aced172000-08-15 01:13:23 +0000701 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000702 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000703 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000704 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000705 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000706 if self.save_warnings_filters is not None:
707 warnings.filters[:] = self.save_warnings_filters
708 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000709 debugger = self.debugger
710 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000711 self.tkconsole.beginexecuting()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000712 if not debugger and self.rpcclt is not None:
713 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
714 (code,), {})
715 elif debugger:
716 debugger.run(code, self.locals)
717 else:
718 exec code in self.locals
719 except SystemExit:
720 if not self.tkconsole.closing:
721 if tkMessageBox.askyesno(
722 "Exit?",
723 "Do you want to exit altogether?",
724 default="yes",
725 master=self.tkconsole.text):
Kurt B. Kaiserf137e1d2006-08-16 07:04:17 +0000726 raise
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000727 else:
728 self.showtraceback()
729 else:
730 raise
731 except:
732 if use_subprocess:
733 print >>self.tkconsole.stderr, \
734 "IDLE internal error in runcode()"
David Scherer7aced172000-08-15 01:13:23 +0000735 self.showtraceback()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000736 self.tkconsole.endexecuting()
737 else:
738 if self.tkconsole.canceled:
739 self.tkconsole.canceled = False
740 print >>self.tkconsole.stderr, "KeyboardInterrupt"
741 else:
742 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000743 finally:
744 if not use_subprocess:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000745 try:
746 self.tkconsole.endexecuting()
747 except AttributeError: # shell may have closed
748 pass
David Scherer7aced172000-08-15 01:13:23 +0000749
750 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000751 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000752 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000753
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000754 def display_port_binding_error(self):
755 tkMessageBox.showerror(
756 "Port Binding Error",
757 "IDLE can't bind TCP/IP port 8833, which is necessary to "
758 "communicate with its Python execution server. Either "
759 "no networking is installed on this computer or another "
760 "process (another IDLE?) is using the port. Run IDLE with the -n "
761 "command line switch to start without a subprocess and refer to "
762 "Help/IDLE Help 'Running without a subprocess' for further "
763 "details.",
764 master=self.tkconsole.text)
765
766 def display_no_subprocess_error(self):
767 tkMessageBox.showerror(
768 "Subprocess Startup Error",
769 "IDLE's subprocess didn't make connection. Either IDLE can't "
770 "start a subprocess or personal firewall software is blocking "
771 "the connection.",
772 master=self.tkconsole.text)
773
774 def display_executing_dialog(self):
775 tkMessageBox.showerror(
776 "Already executing",
777 "The Python Shell window is already executing a command; "
778 "please wait until it is finished.",
779 master=self.tkconsole.text)
780
781
David Scherer7aced172000-08-15 01:13:23 +0000782class PyShell(OutputWindow):
783
784 shell_title = "Python Shell"
785
786 # Override classes
787 ColorDelegator = ModifiedColorDelegator
788 UndoDelegator = ModifiedUndoDelegator
789
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000790 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000791 menu_specs = [
792 ("file", "_File"),
793 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000794 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000795 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000796 ("windows", "_Windows"),
797 ("help", "_Help"),
798 ]
David Scherer7aced172000-08-15 01:13:23 +0000799
Ronald Oussoren19302d92006-06-11 14:33:36 +0000800 if macosxSupport.runningAsOSXApp():
801 del menu_specs[-3]
802 menu_specs[-2] = ("windows", "_Window")
803
804
David Scherer7aced172000-08-15 01:13:23 +0000805 # New classes
806 from IdleHistory import History
807
808 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000809 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000810 ms = self.menu_specs
811 if ms[2][0] != "shell":
Kurt B. Kaiser7ae35482006-08-16 21:45:59 +0000812 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000813 self.interp = ModifiedInterpreter(self)
814 if flist is None:
815 root = Tk()
816 fixwordbreaks(root)
817 root.withdraw()
818 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000819 #
David Scherer7aced172000-08-15 01:13:23 +0000820 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000821 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000822## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
823 self.usetabs = True
824 # indentwidth must be 8 when using tabs. See note in EditorWindow:
825 self.indentwidth = 8
826 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000827 #
David Scherer7aced172000-08-15 01:13:23 +0000828 text = self.text
829 text.configure(wrap="char")
830 text.bind("<<newline-and-indent>>", self.enter_callback)
831 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
832 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000833 text.bind("<<end-of-file>>", self.eof_callback)
834 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000835 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000836 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000837 if use_subprocess:
838 text.bind("<<view-restart>>", self.view_restart_mark)
839 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000840 #
David Scherer7aced172000-08-15 01:13:23 +0000841 self.save_stdout = sys.stdout
842 self.save_stderr = sys.stderr
843 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000844 import IOBinding
845 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
846 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
847 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000848 if not use_subprocess:
849 sys.stdout = self.stdout
850 sys.stderr = self.stderr
851 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000852 #
David Scherer7aced172000-08-15 01:13:23 +0000853 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000854 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000855 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000856
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000857 def get_standard_extension_names(self):
858 return idleConf.GetExtensions(shell_only=True)
859
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000860 reading = False
861 executing = False
862 canceled = False
863 endoffile = False
864 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000865
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000866 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000867 global warning_stream
868 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000869
870 def get_warning_stream(self):
871 return warning_stream
872
David Scherer7aced172000-08-15 01:13:23 +0000873 def toggle_debugger(self, event=None):
874 if self.executing:
875 tkMessageBox.showerror("Don't debug now",
876 "You can only toggle the debugger when idle",
877 master=self.text)
878 self.set_debugger_indicator()
879 return "break"
880 else:
881 db = self.interp.getdebugger()
882 if db:
883 self.close_debugger()
884 else:
885 self.open_debugger()
886
887 def set_debugger_indicator(self):
888 db = self.interp.getdebugger()
889 self.setvar("<<toggle-debugger>>", not not db)
890
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000891 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000892 pass # All we need is the variable
893
894 def close_debugger(self):
895 db = self.interp.getdebugger()
896 if db:
897 self.interp.setdebugger(None)
898 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000899 if self.interp.rpcclt:
900 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000901 self.resetoutput()
902 self.console.write("[DEBUG OFF]\n")
903 sys.ps1 = ">>> "
904 self.showprompt()
905 self.set_debugger_indicator()
906
907 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000908 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000909 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
910 self)
911 else:
912 dbg_gui = Debugger.Debugger(self)
913 self.interp.setdebugger(dbg_gui)
914 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000915 sys.ps1 = "[DEBUG ON]\n>>> "
916 self.showprompt()
917 self.set_debugger_indicator()
918
David Scherer7aced172000-08-15 01:13:23 +0000919 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000920 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000921 self.resetoutput()
922 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000923
924 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000925 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000926 self.executing = 0
927 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000928 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000929
930 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000931 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000932 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000933 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000934 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000935 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000936 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000937 parent=self.text)
Benjamin Peterson5b63acd2008-03-29 15:24:25 +0000938 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000939 return "cancel"
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000940 if self.reading:
941 self.top.quit()
942 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000943 self.closing = True
944 # Wait for poll_subprocess() rescheduling to stop
945 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000946
947 def close2(self):
948 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000949
950 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000951 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000952 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000953 if use_subprocess:
954 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000955 # Restore std streams
956 sys.stdout = self.save_stdout
957 sys.stderr = self.save_stderr
958 sys.stdin = self.save_stdin
959 # Break cycles
960 self.interp = None
961 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000962 self.flist.pyshell = None
963 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000964 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000965
966 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000967 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000968 return True
David Scherer7aced172000-08-15 01:13:23 +0000969
970 def short_title(self):
971 return self.shell_title
972
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000973 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000974 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000975
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000976 firewallmessage = """
977 ****************************************************************
978 Personal firewall software may warn about the connection IDLE
979 makes to its subprocess using this computer's internal loopback
980 interface. This connection is not visible on any external
981 interface and no data is sent to or received from the Internet.
982 ****************************************************************
983 """
984
David Scherer7aced172000-08-15 01:13:23 +0000985 def begin(self):
986 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000987 if use_subprocess:
988 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000989 client = self.interp.start_subprocess()
990 if not client:
991 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000992 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000993 else:
994 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000995 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000996 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000997 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000998 self.showprompt()
Georg Brandl6634bf22008-05-20 07:13:37 +0000999 import Tkinter
1000 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001001 return True
David Scherer7aced172000-08-15 01:13:23 +00001002
1003 def readline(self):
1004 save = self.reading
1005 try:
1006 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001007 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001008 finally:
1009 self.reading = save
1010 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001011 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1012 line = "\n"
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001013 if isinstance(line, unicode):
1014 import IOBinding
1015 try:
1016 line = line.encode(IOBinding.encoding)
1017 except UnicodeError:
1018 pass
David Scherer7aced172000-08-15 01:13:23 +00001019 self.resetoutput()
1020 if self.canceled:
1021 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001022 if not use_subprocess:
1023 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001024 if self.endoffile:
1025 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001026 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001027 return line
1028
1029 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001030 return True
David Scherer7aced172000-08-15 01:13:23 +00001031
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001032 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001033 try:
1034 if self.text.compare("sel.first", "!=", "sel.last"):
1035 return # Active selection -- always use default binding
1036 except:
1037 pass
1038 if not (self.executing or self.reading):
1039 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001040 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001041 self.showprompt()
1042 return "break"
1043 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001044 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001045 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001046 if self.interp.getdebugger():
1047 self.interp.restart_subprocess()
1048 else:
1049 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001050 if self.reading:
1051 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001052 return "break"
1053
1054 def eof_callback(self, event):
1055 if self.executing and not self.reading:
1056 return # Let the default binding (delete next char) take over
1057 if not (self.text.compare("iomark", "==", "insert") and
1058 self.text.compare("insert", "==", "end-1c")):
1059 return # Let the default binding (delete next char) take over
1060 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001061 self.resetoutput()
1062 self.close()
1063 else:
1064 self.canceled = 0
1065 self.endoffile = 1
1066 self.top.quit()
1067 return "break"
1068
David Scherer7aced172000-08-15 01:13:23 +00001069 def linefeed_callback(self, event):
1070 # Insert a linefeed without entering anything (still autoindented)
1071 if self.reading:
1072 self.text.insert("insert", "\n")
1073 self.text.see("insert")
1074 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001075 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001076 return "break"
1077
1078 def enter_callback(self, event):
1079 if self.executing and not self.reading:
1080 return # Let the default binding (insert '\n') take over
1081 # If some text is selected, recall the selection
1082 # (but only if this before the I/O mark)
1083 try:
1084 sel = self.text.get("sel.first", "sel.last")
1085 if sel:
1086 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001087 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001088 return "break"
1089 except:
1090 pass
1091 # If we're strictly before the line containing iomark, recall
1092 # the current line, less a leading prompt, less leading or
1093 # trailing whitespace
1094 if self.text.compare("insert", "<", "iomark linestart"):
1095 # Check if there's a relevant stdin range -- if so, use it
1096 prev = self.text.tag_prevrange("stdin", "insert")
1097 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001098 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001099 return "break"
1100 next = self.text.tag_nextrange("stdin", "insert")
1101 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001102 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001103 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001104 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001105 indices = self.text.tag_nextrange("console", "insert linestart")
1106 if indices and \
1107 self.text.compare(indices[0], "<=", "insert linestart"):
1108 self.recall(self.text.get(indices[1], "insert lineend"), event)
1109 else:
1110 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001111 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001112 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001113 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001114 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001115 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001116 # If we're in the current input and there's only whitespace
1117 # beyond the cursor, erase that whitespace first
1118 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001119 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001120 self.text.delete("insert", "end-1c")
1121 # If we're in the current input before its last line,
1122 # insert a newline right at the insert point
1123 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001124 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001125 return "break"
1126 # We're in the last line; append a newline and submit it
1127 self.text.mark_set("insert", "end-1c")
1128 if self.reading:
1129 self.text.insert("insert", "\n")
1130 self.text.see("insert")
1131 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001132 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001133 self.text.tag_add("stdin", "iomark", "end-1c")
1134 self.text.update_idletasks()
1135 if self.reading:
1136 self.top.quit() # Break out of recursive mainloop() in raw_input()
1137 else:
1138 self.runit()
1139 return "break"
1140
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001141 def recall(self, s, event):
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001142 # remove leading and trailing empty or whitespace lines
1143 s = re.sub(r'^\s*\n', '' , s)
1144 s = re.sub(r'\n\s*$', '', s)
1145 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001146 self.text.undo_block_start()
1147 try:
1148 self.text.tag_remove("sel", "1.0", "end")
1149 self.text.mark_set("insert", "end-1c")
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001150 prefix = self.text.get("insert linestart", "insert")
1151 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001152 self.newline_and_indent_event(event)
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001153 prefix = self.text.get("insert linestart", "insert")
1154 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001155 if len(lines) > 1:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001156 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1157 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001158 for line in lines[1:]:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001159 if line.startswith(orig_base_indent):
1160 # replace orig base indentation with new indentation
1161 line = new_base_indent + line[len(orig_base_indent):]
1162 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001163 finally:
1164 self.text.see("insert")
1165 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001166
1167 def runit(self):
1168 line = self.text.get("iomark", "end-1c")
1169 # Strip off last newline and surrounding whitespace.
1170 # (To allow you to hit return twice to end a statement.)
1171 i = len(line)
1172 while i > 0 and line[i-1] in " \t":
1173 i = i-1
1174 if i > 0 and line[i-1] == "\n":
1175 i = i-1
1176 while i > 0 and line[i-1] in " \t":
1177 i = i-1
1178 line = line[:i]
1179 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001180
David Scherer7aced172000-08-15 01:13:23 +00001181 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001182 if self.interp.rpcclt:
1183 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001184 try:
1185 sys.last_traceback
1186 except:
1187 tkMessageBox.showerror("No stack trace",
1188 "There is no stack trace yet.\n"
1189 "(sys.last_traceback is not defined)",
1190 master=self.text)
1191 return
1192 from StackViewer import StackBrowser
1193 sv = StackBrowser(self.root, self.flist)
1194
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001195 def view_restart_mark(self, event=None):
1196 self.text.see("iomark")
1197 self.text.see("restart")
1198
1199 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001200 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001201
David Scherer7aced172000-08-15 01:13:23 +00001202 def showprompt(self):
1203 self.resetoutput()
1204 try:
1205 s = str(sys.ps1)
1206 except:
1207 s = ""
1208 self.console.write(s)
1209 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001210 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001211 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001212
1213 def resetoutput(self):
1214 source = self.text.get("iomark", "end-1c")
1215 if self.history:
1216 self.history.history_store(source)
1217 if self.text.get("end-2c") != "\n":
1218 self.text.insert("end-1c", "\n")
1219 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001220 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001221 sys.stdout.softspace = 0
1222
1223 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001224 try:
1225 self.text.mark_gravity("iomark", "right")
1226 OutputWindow.write(self, s, tags, "iomark")
1227 self.text.mark_gravity("iomark", "left")
1228 except:
1229 pass
David Scherer7aced172000-08-15 01:13:23 +00001230 if self.canceled:
1231 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001232 if not use_subprocess:
1233 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001234
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +00001235class PseudoFile(object):
David Scherer7aced172000-08-15 01:13:23 +00001236
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001237 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001238 self.shell = shell
1239 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001240 self.softspace = 0
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001241 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001242
1243 def write(self, s):
1244 self.shell.write(s, self.tags)
1245
1246 def writelines(self, l):
1247 map(self.write, l)
1248
1249 def flush(self):
1250 pass
1251
1252 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001253 return True
David Scherer7aced172000-08-15 01:13:23 +00001254
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001255
David Scherer7aced172000-08-15 01:13:23 +00001256usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001257
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001258USAGE: idle [-deins] [-t title] [file]*
1259 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1260 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001261
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001262 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001263 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001264
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001265The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001266
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001267 -e open an edit window
1268 -i open a shell window
1269
1270The following options imply -i and will open a shell:
1271
1272 -c cmd run the command in a shell, or
1273 -r file run script from file
1274
1275 -d enable the debugger
1276 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1277 -t title set title of shell window
1278
1279A default edit window will be bypassed when -c, -r, or - are used.
1280
1281[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1282
1283Examples:
1284
1285idle
1286 Open an edit window or shell depending on IDLE's configuration.
1287
1288idle foo.py foobar.py
1289 Edit the files, also open a shell if configured to start with shell.
1290
1291idle -est "Baz" foo.py
1292 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1293 window with the title "Baz".
1294
1295idle -c "import sys; print sys.argv" "foo"
1296 Open a shell window and run the command, passing "-c" in sys.argv[0]
1297 and "foo" in sys.argv[1].
1298
1299idle -d -s -r foo.py "Hello World"
1300 Open a shell window, run a startup script, enable the debugger, and
1301 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1302 sys.argv[1].
1303
1304echo "import sys; print sys.argv" | idle - "foobar"
1305 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1306 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001307"""
1308
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001309def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001310 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001311
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001312 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001313 enable_shell = False
1314 enable_edit = False
1315 debug = False
1316 cmd = None
1317 script = None
1318 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001319 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001320 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001321 except getopt.error, msg:
1322 sys.stderr.write("Error: %s\n" % str(msg))
1323 sys.stderr.write(usage_msg)
1324 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001325 for o, a in opts:
1326 if o == '-c':
1327 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001328 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001329 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001330 debug = True
1331 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001332 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001333 enable_edit = True
1334 if o == '-h':
1335 sys.stdout.write(usage_msg)
1336 sys.exit()
1337 if o == '-i':
1338 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001339 if o == '-n':
1340 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001341 if o == '-r':
1342 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001343 if os.path.isfile(script):
1344 pass
1345 else:
1346 print "No script file: ", script
1347 sys.exit()
1348 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001349 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001350 startup = True
1351 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001352 if o == '-t':
1353 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001354 enable_shell = True
1355 if args and args[0] == '-':
1356 cmd = sys.stdin.read()
1357 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001358 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001359 for i in range(len(sys.path)):
1360 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001361 if args and args[0] == '-':
1362 sys.argv = [''] + args[1:]
1363 elif cmd:
1364 sys.argv = ['-c'] + args
1365 elif script:
1366 sys.argv = [script] + args
1367 elif args:
1368 enable_edit = True
1369 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001370 for filename in args:
1371 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001372 for dir in pathx:
1373 dir = os.path.abspath(dir)
1374 if not dir in sys.path:
1375 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001376 else:
1377 dir = os.getcwd()
1378 if not dir in sys.path:
1379 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001380 # check the IDLE settings configuration (but command line overrides)
1381 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001382 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001383 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001384 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001385 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001386 root = Tk(className="Idle")
Ronald Oussoren19302d92006-06-11 14:33:36 +00001387
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001388 fixwordbreaks(root)
1389 root.withdraw()
1390 flist = PyShellFileList(root)
Ronald Oussoren19302d92006-06-11 14:33:36 +00001391 macosxSupport.setupApp(root, flist)
1392
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001393 if enable_edit:
1394 if not (cmd or script):
1395 for filename in args:
1396 flist.open(filename)
1397 if not args:
1398 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001399 if enable_shell:
Ronald Oussoren19302d92006-06-11 14:33:36 +00001400 shell = flist.open_shell()
1401 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001402 return # couldn't open shell
Ronald Oussoren19302d92006-06-11 14:33:36 +00001403
1404 if macosxSupport.runningAsOSXApp() and flist.dict:
1405 # On OSX: when the user has double-clicked on a file that causes
Tim Peters4f96f1f2006-06-11 19:42:51 +00001406 # IDLE to be launched the shell window will open just in front of
1407 # the file she wants to see. Lower the interpreter window when
Ronald Oussoren19302d92006-06-11 14:33:36 +00001408 # there are open files.
1409 shell.top.lower()
1410
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001411 shell = flist.pyshell
1412 # handle remaining options:
1413 if debug:
1414 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001415 if startup:
1416 filename = os.environ.get("IDLESTARTUP") or \
1417 os.environ.get("PYTHONSTARTUP")
1418 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001419 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001420 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001421 shell.interp.runcommand("""if 1:
1422 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001423 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001424 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001425 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001426 if cmd:
1427 shell.interp.execsource(cmd)
1428 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001429 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001430 shell.interp.execfile(script)
Ronald Oussoren19302d92006-06-11 14:33:36 +00001431
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001432 root.mainloop()
1433 root.destroy()
1434
David Scherer7aced172000-08-15 01:13:23 +00001435if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001436 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001437 main()