blob: dc47f07d32e1e2cddd5e58da9e47d67d5e3ab83e [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
Kurt B. Kaiser0930c432002-12-06 21:45:24 +000014import exceptions
David Scherer7aced172000-08-15 01:13:23 +000015
16import linecache
17from code import InteractiveInterpreter
18
19from Tkinter import *
20import tkMessageBox
21
Tony Lowndsb693f8e2002-12-24 17:21:43 +000022# Preserve 2.2 compatibility for Mac OS X:
23import boolcheck
24
David Scherer7aced172000-08-15 01:13:23 +000025from EditorWindow import EditorWindow, fixwordbreaks
26from FileList import FileList
27from ColorDelegator import ColorDelegator
28from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000029from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000030from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000031import idlever
32
Chui Tey5d2af632002-05-26 13:36:41 +000033import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000034import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000035import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000036
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000037IDENTCHARS = string.ascii_letters + string.digits + "_"
38
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000039try:
40 from signal import SIGTERM
41except ImportError:
42 SIGTERM = 15
43
Chui Tey5d2af632002-05-26 13:36:41 +000044# Change warnings module to write to sys.__stderr__
45try:
46 import warnings
47except ImportError:
48 pass
49else:
50 def idle_showwarning(message, category, filename, lineno):
51 file = sys.__stderr__
52 file.write(warnings.formatwarning(message, category, filename, lineno))
53 warnings.showwarning = idle_showwarning
54
Kurt B. Kaiser81885592002-11-29 22:10:53 +000055def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000056 """Extend linecache.checkcache to preserve the <pyshell#...> entries
57
Kurt B. Kaiser81885592002-11-29 22:10:53 +000058 Rather than repeating the linecache code, patch it to save the pyshell#
59 entries, call the original linecache.checkcache(), and then restore the
60 saved entries. Assigning the orig_checkcache keyword arg freezes its value
61 at definition time to the (original) method linecache.checkcache(), i.e.
62 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000063
64 """
David Scherer7aced172000-08-15 01:13:23 +000065 cache = linecache.cache
66 save = {}
67 for filename in cache.keys():
68 if filename[:1] + filename[-1:] == '<>':
69 save[filename] = cache[filename]
70 orig_checkcache()
71 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000072
Kurt B. Kaiser81885592002-11-29 22:10:53 +000073# Patch linecache.checkcache():
74linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000075
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000076
David Scherer7aced172000-08-15 01:13:23 +000077class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000078 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000079
David Scherer7aced172000-08-15 01:13:23 +000080 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000081 self.breakpoints = []
David Scherer7aced172000-08-15 01:13:23 +000082 apply(EditorWindow.__init__, (self,) + args)
83 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000084 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +000085 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
86
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000087 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
88 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +000089 # whenever a file is changed, restore breakpoints
90 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000091 def filename_changed_hook(old_hook=self.io.filename_change_hook,
92 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +000093 self.restore_file_breaks()
94 old_hook()
95 self.io.set_filename_change_hook(filename_changed_hook)
96
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000097 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
98 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +000099
Chui Teya2adb0f2002-11-04 22:14:54 +0000100 def set_breakpoint(self, lineno):
101 text = self.text
102 filename = self.io.filename
103 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
104 try:
105 i = self.breakpoints.index(lineno)
106 except ValueError: # only add if missing, i.e. do once
107 self.breakpoints.append(lineno)
108 try: # update the subprocess debugger
109 debug = self.flist.pyshell.interp.debugger
110 debug.set_breakpoint_here(filename, lineno)
111 except: # but debugger may not be active right now....
112 pass
113
David Scherer7aced172000-08-15 01:13:23 +0000114 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000115 text = self.text
116 filename = self.io.filename
117 if not filename:
118 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000119 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000120 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000121 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000122
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000123 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000124 text = self.text
125 filename = self.io.filename
126 if not filename:
127 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000128 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000129 lineno = int(float(text.index("insert")))
130 try:
131 self.breakpoints.remove(lineno)
132 except:
133 pass
134 text.tag_remove("BREAK", "insert linestart",\
135 "insert lineend +1char")
136 try:
137 debug = self.flist.pyshell.interp.debugger
138 debug.clear_breakpoint_here(filename, lineno)
139 except:
140 pass
141
142 def clear_file_breaks(self):
143 if self.breakpoints:
144 text = self.text
145 filename = self.io.filename
146 if not filename:
147 text.bell()
148 return
149 self.breakpoints = []
150 text.tag_remove("BREAK", "1.0", END)
151 try:
152 debug = self.flist.pyshell.interp.debugger
153 debug.clear_file_breaks(filename)
154 except:
155 pass
156
Chui Teya2adb0f2002-11-04 22:14:54 +0000157 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000158 "Save breakpoints when file is saved"
159 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
160 # be run. The breaks are saved at that time. If we introduce
161 # a temporary file save feature the save breaks functionality
162 # needs to be re-verified, since the breaks at the time the
163 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000164 # permanent save of the file. Currently, a break introduced
165 # after a save will be effective, but not persistent.
166 # This is necessary to keep the saved breaks synched with the
167 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000168 #
169 # Breakpoints are set as tagged ranges in the text. Certain
170 # kinds of edits cause these ranges to be deleted: Inserting
171 # or deleting a line just before a breakpoint, and certain
172 # deletions prior to a breakpoint. These issues need to be
173 # investigated and understood. It's not clear if they are
174 # Tk issues or IDLE issues, or whether they can actually
175 # be fixed. Since a modified file has to be saved before it is
176 # run, and since self.breakpoints (from which the subprocess
177 # debugger is loaded) is updated during the save, the visible
178 # breaks stay synched with the subprocess even if one of these
179 # unexpected breakpoint deletions occurs.
180 breaks = self.breakpoints
181 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000182 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000183 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000184 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000185 lines = []
186 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000187 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000188 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000189 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000190 self.update_breakpoints()
191 breaks = self.breakpoints
192 if breaks:
193 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000194 new_file.close()
195
196 def restore_file_breaks(self):
197 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000198 filename = self.io.filename
199 if filename is None:
200 return
Chui Tey69371d62002-11-04 23:39:45 +0000201 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000202 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000203 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000204 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000205 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000206 for breakpoint_linenumber in breakpoint_linenumbers:
207 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000208
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 def update_breakpoints(self):
210 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000211 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000212 ranges = text.tag_ranges("BREAK")
213 linenumber_list = self.ranges_to_linenumbers(ranges)
214 self.breakpoints = linenumber_list
215
216 def ranges_to_linenumbers(self, ranges):
217 lines = []
218 for index in range(0, len(ranges), 2):
219 lineno = int(float(ranges[index]))
220 end = int(float(ranges[index+1]))
221 while lineno < end:
222 lines.append(lineno)
223 lineno += 1
224 return lines
225
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000226# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000227# def saved_change_hook(self):
228# "Extend base method - clear breaks if module is modified"
229# if not self.get_saved():
230# self.clear_file_breaks()
231# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000232
233 def _close(self):
234 "Extend base method - clear breaks when module is closed"
235 self.clear_file_breaks()
236 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000237
David Scherer7aced172000-08-15 01:13:23 +0000238
239class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000240 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000241
242 EditorWindow = PyShellEditorWindow
243
244 pyshell = None
245
246 def open_shell(self, event=None):
247 if self.pyshell:
248 self.pyshell.wakeup()
249 else:
250 self.pyshell = PyShell(self)
251 self.pyshell.begin()
252 return self.pyshell
253
254
255class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000256 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000257
Steven M. Gavab77d3432002-03-02 07:16:21 +0000258 def __init__(self):
259 ColorDelegator.__init__(self)
260 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000261
262 def recolorize_main(self):
263 self.tag_remove("TODO", "1.0", "iomark")
264 self.tag_add("SYNC", "1.0", "iomark")
265 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000266
Steven M. Gavab77d3432002-03-02 07:16:21 +0000267 def LoadTagDefs(self):
268 ColorDelegator.LoadTagDefs(self)
269 theme = idleConf.GetOption('main','Theme','name')
270 self.tagdefs.update({
271 "stdin": {'background':None,'foreground':None},
272 "stdout": idleConf.GetHighlight(theme, "stdout"),
273 "stderr": idleConf.GetHighlight(theme, "stderr"),
274 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000275 None: idleConf.GetHighlight(theme, "normal"),
276 })
David Scherer7aced172000-08-15 01:13:23 +0000277
David Scherer7aced172000-08-15 01:13:23 +0000278class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000279 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000280
281 def insert(self, index, chars, tags=None):
282 try:
283 if self.delegate.compare(index, "<", "iomark"):
284 self.delegate.bell()
285 return
286 except TclError:
287 pass
288 UndoDelegator.insert(self, index, chars, tags)
289
290 def delete(self, index1, index2=None):
291 try:
292 if self.delegate.compare(index1, "<", "iomark"):
293 self.delegate.bell()
294 return
295 except TclError:
296 pass
297 UndoDelegator.delete(self, index1, index2)
298
299class ModifiedInterpreter(InteractiveInterpreter):
300
301 def __init__(self, tkconsole):
302 self.tkconsole = tkconsole
303 locals = sys.modules['__main__'].__dict__
304 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000305 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000306
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000307 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000308 rpcclt = None
309 rpcpid = None
310
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000311 def spawn_subprocess(self):
Tony Lowndsf53dec22002-12-20 04:24:43 +0000312 args = self.build_subprocess_arglist()
Chui Tey5d2af632002-05-26 13:36:41 +0000313 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000314
Tony Lowndsf53dec22002-12-20 04:24:43 +0000315 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000316 w = ['-W' + s for s in sys.warnoptions]
317 # Maybe IDLE is installed and is being accessed via sys.path,
318 # or maybe it's not installed and the idle.py script is being
319 # run from the IDLE source directory.
320 if __name__ == 'idlelib.PyShell':
321 command = "__import__('idlelib.run').run.main()"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000322 else:
Tony Lownds2398d572003-05-13 15:28:21 +0000323 command = "__import__('run').main()"
324 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000325
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000326 def start_subprocess(self):
327 addr = ("localhost", self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000328 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000329 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000330 time.sleep(i)
331 try:
332 self.rpcclt = rpc.RPCClient(addr)
333 break
334 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000335 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000336 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000337 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000338 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000339 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000340 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000341 # Accept the connection from the Python execution server
342 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000343 self.rpcclt.register("stdin", self.tkconsole)
344 self.rpcclt.register("stdout", self.tkconsole.stdout)
345 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000346 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000347 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000348 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000349 self.poll_subprocess()
350
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000351 def restart_subprocess(self):
352 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000353 debug = self.getdebugger()
354 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000355 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000356 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000357 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
358 except:
359 pass
360 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000361 self.rpcclt.close()
362 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000363 console = self.tkconsole
364 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000365 self.spawn_subprocess()
366 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000367 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000368 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000369 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000370 halfbar = ((int(console.width) - 16) // 2) * '='
371 console.write(halfbar + ' RESTART ' + halfbar)
372 console.text.mark_set("restart", "end-1c")
373 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000374 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000375 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000376 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000377 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000378 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000379 # reload remote debugger breakpoints for all PyShellEditWindows
380 debug.load_breakpoints()
381
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000382 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000383 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000384
385 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000386 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000387
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000388 def kill_subprocess(self):
389 self.rpcclt.close()
390 self.unix_terminate()
391 self.tkconsole.executing = False
392 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000393
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000394 def unix_terminate(self):
395 "UNIX: make sure subprocess is terminated and collect status"
396 if hasattr(os, 'kill'):
397 try:
398 os.kill(self.rpcpid, SIGTERM)
399 except OSError:
400 # process already terminated:
401 return
402 else:
403 try:
404 os.waitpid(self.rpcpid, 0)
405 except OSError:
406 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000407
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000408 def transfer_path(self):
409 self.runcommand("""if 1:
410 import sys as _sys
411 _sys.path = %s
412 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000413 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
414 __builtins__.quit = __builtins__.exit = _msg
415 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000416 \n""" % `sys.path`)
417
Chui Tey5d2af632002-05-26 13:36:41 +0000418 active_seq = None
419
420 def poll_subprocess(self):
421 clt = self.rpcclt
422 if clt is None:
423 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000424 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000425 response = clt.pollresponse(self.active_seq, wait=0.05)
426 except (EOFError, IOError, KeyboardInterrupt):
427 # lost connection or subprocess terminated itself, restart
428 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000429 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000430 self.restart_subprocess()
431 self.tkconsole.endexecuting()
Chui Tey5d2af632002-05-26 13:36:41 +0000432 if response:
433 self.tkconsole.resetoutput()
434 self.active_seq = None
435 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000436 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000437 if how == "OK":
438 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000439 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000440 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000441 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
442 self.remote_stack_viewer()
443 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000444 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
445 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000446 print >>console, errmsg, what
447 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000448 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000449 # Reschedule myself
450 if not self.tkconsole.closing:
451 self.tkconsole.text.after(self.tkconsole.pollinterval,
452 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000453
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000454 debugger = None
455
456 def setdebugger(self, debugger):
457 self.debugger = debugger
458
459 def getdebugger(self):
460 return self.debugger
461
Chui Tey5d2af632002-05-26 13:36:41 +0000462 def remote_stack_viewer(self):
463 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000464 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000465 if oid is None:
466 self.tkconsole.root.bell()
467 return
468 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
469 from TreeWidget import ScrolledCanvas, TreeNode
470 top = Toplevel(self.tkconsole.root)
471 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
472 sc.frame.pack(expand=1, fill="both")
473 node = TreeNode(sc.canvas, None, item)
474 node.expand()
475 # XXX Should GC the remote tree when closing the window
476
David Scherer7aced172000-08-15 01:13:23 +0000477 gid = 0
478
479 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000480 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000481 filename = self.stuffsource(source)
482 self.execfile(filename, source)
483
484 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000485 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000486 if source is None:
487 source = open(filename, "r").read()
488 try:
489 code = compile(source, filename, "exec")
490 except (OverflowError, SyntaxError):
491 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000492 tkerr = self.tkconsole.stderr
493 print>>tkerr, '*** Error in script or command!\n'
494 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000495 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000496 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000497 else:
498 self.runcode(code)
499
500 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000501 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000502 filename = self.stuffsource(source)
503 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000504 self.save_warnings_filters = warnings.filters[:]
505 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000506 if isinstance(source, types.UnicodeType):
507 import IOBinding
508 try:
509 source = source.encode(IOBinding.encoding)
510 except UnicodeError:
511 self.tkconsole.resetoutput()
512 self.write("Unsupported characters in input")
513 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000514 try:
515 return InteractiveInterpreter.runsource(self, source, filename)
516 finally:
517 if self.save_warnings_filters is not None:
518 warnings.filters[:] = self.save_warnings_filters
519 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000520
521 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000522 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000523 filename = "<pyshell#%d>" % self.gid
524 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000525 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000526 linecache.cache[filename] = len(source)+1, 0, lines, filename
527 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000528
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000529 def prepend_syspath(self, filename):
530 "Prepend sys.path with file's directory if not already included"
531 self.runcommand("""if 1:
532 _filename = %s
533 import sys as _sys
534 from os.path import dirname as _dirname
535 _dir = _dirname(_filename)
536 if not _dir in _sys.path:
537 _sys.path.insert(0, _dir)
538 del _filename, _sys, _dirname, _dir
539 \n""" % `filename`)
540
David Scherer7aced172000-08-15 01:13:23 +0000541 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000542 """Extend base class method: Add Colorizing
543
544 Color the offending position instead of printing it and pointing at it
545 with a caret.
546
547 """
David Scherer7aced172000-08-15 01:13:23 +0000548 text = self.tkconsole.text
549 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000550 if stuff:
551 msg, lineno, offset, line = stuff
552 if lineno == 1:
553 pos = "iomark + %d chars" % (offset-1)
554 else:
555 pos = "iomark linestart + %d lines + %d chars" % \
556 (lineno-1, offset-1)
557 text.tag_add("ERROR", pos)
558 text.see(pos)
559 char = text.get(pos)
560 if char and char in IDENTCHARS:
561 text.tag_add("ERROR", pos + " wordstart", pos)
562 self.tkconsole.resetoutput()
563 self.write("SyntaxError: %s\n" % str(msg))
564 else:
David Scherer7aced172000-08-15 01:13:23 +0000565 self.tkconsole.resetoutput()
566 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000567 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000568
569 def unpackerror(self):
570 type, value, tb = sys.exc_info()
571 ok = type is SyntaxError
572 if ok:
573 try:
574 msg, (dummy_filename, lineno, offset, line) = value
575 except:
576 ok = 0
577 if ok:
578 return msg, lineno, offset, line
579 else:
580 return None
581
582 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000583 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000584 self.tkconsole.resetoutput()
585 self.checklinecache()
586 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000587 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
588 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000589
590 def checklinecache(self):
591 c = linecache.cache
592 for key in c.keys():
593 if key[:1] + key[-1:] != "<>":
594 del c[key]
595
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000596 def display_executing_dialog(self):
597 tkMessageBox.showerror(
598 "Already executing",
599 "The Python Shell window is already executing a command; "
600 "please wait until it is finished.",
601 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000602
Chui Tey5d2af632002-05-26 13:36:41 +0000603 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000604 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000605 # The code better not raise an exception!
606 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000607 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000608 return 0
609 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000610 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000611 else:
612 exec code in self.locals
613 return 1
614
David Scherer7aced172000-08-15 01:13:23 +0000615 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000616 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000617 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000618 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000619 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000620 if self.save_warnings_filters is not None:
621 warnings.filters[:] = self.save_warnings_filters
622 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000623 debugger = self.debugger
624 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000625 self.tkconsole.beginexecuting()
626 try:
627 if not debugger and self.rpcclt is not None:
628 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
629 (code,), {})
630 elif debugger:
631 debugger.run(code, self.locals)
632 else:
633 exec code in self.locals
634 except SystemExit:
635 if tkMessageBox.askyesno(
636 "Exit?",
637 "Do you want to exit altogether?",
638 default="yes",
639 master=self.tkconsole.text):
640 raise
641 else:
642 self.showtraceback()
643 except:
David Scherer7aced172000-08-15 01:13:23 +0000644 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000645 finally:
646 if not use_subprocess:
647 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000648
649 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000650 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000651 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000652
David Scherer7aced172000-08-15 01:13:23 +0000653class PyShell(OutputWindow):
654
655 shell_title = "Python Shell"
656
657 # Override classes
658 ColorDelegator = ModifiedColorDelegator
659 UndoDelegator = ModifiedUndoDelegator
660
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000661 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000662 menu_specs = [
663 ("file", "_File"),
664 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000665 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000666 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000667 ("windows", "_Windows"),
668 ("help", "_Help"),
669 ]
David Scherer7aced172000-08-15 01:13:23 +0000670
671 # New classes
672 from IdleHistory import History
673
674 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000675 if use_subprocess:
676 self.menu_specs.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000677 self.interp = ModifiedInterpreter(self)
678 if flist is None:
679 root = Tk()
680 fixwordbreaks(root)
681 root.withdraw()
682 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000683 #
David Scherer7aced172000-08-15 01:13:23 +0000684 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000685 #
David Scherer7aced172000-08-15 01:13:23 +0000686 import __builtin__
687 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000688 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000689 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000690 #
David Scherer7aced172000-08-15 01:13:23 +0000691 text = self.text
692 text.configure(wrap="char")
693 text.bind("<<newline-and-indent>>", self.enter_callback)
694 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
695 text.bind("<<interrupt-execution>>", self.cancel_callback)
696 text.bind("<<beginning-of-line>>", self.home_callback)
697 text.bind("<<end-of-file>>", self.eof_callback)
698 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000699 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000700 text.bind("<<open-python-shell>>", self.flist.open_shell)
701 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000702 if use_subprocess:
703 text.bind("<<view-restart>>", self.view_restart_mark)
704 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000705 #
David Scherer7aced172000-08-15 01:13:23 +0000706 self.save_stdout = sys.stdout
707 self.save_stderr = sys.stderr
708 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000709 self.stdout = PseudoFile(self, "stdout")
710 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000711 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000712 if not use_subprocess:
713 sys.stdout = self.stdout
714 sys.stderr = self.stderr
715 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000716 #
David Scherer7aced172000-08-15 01:13:23 +0000717 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000718 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000719 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000720 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000721 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000722
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000723 reading = False
724 executing = False
725 canceled = False
726 endoffile = False
727 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000728
729 def toggle_debugger(self, event=None):
730 if self.executing:
731 tkMessageBox.showerror("Don't debug now",
732 "You can only toggle the debugger when idle",
733 master=self.text)
734 self.set_debugger_indicator()
735 return "break"
736 else:
737 db = self.interp.getdebugger()
738 if db:
739 self.close_debugger()
740 else:
741 self.open_debugger()
742
743 def set_debugger_indicator(self):
744 db = self.interp.getdebugger()
745 self.setvar("<<toggle-debugger>>", not not db)
746
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000747 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000748 pass # All we need is the variable
749
750 def close_debugger(self):
751 db = self.interp.getdebugger()
752 if db:
753 self.interp.setdebugger(None)
754 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000755 if self.interp.rpcclt:
756 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000757 self.resetoutput()
758 self.console.write("[DEBUG OFF]\n")
759 sys.ps1 = ">>> "
760 self.showprompt()
761 self.set_debugger_indicator()
762
763 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000764 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000765 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
766 self)
767 else:
768 dbg_gui = Debugger.Debugger(self)
769 self.interp.setdebugger(dbg_gui)
770 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000771 sys.ps1 = "[DEBUG ON]\n>>> "
772 self.showprompt()
773 self.set_debugger_indicator()
774
David Scherer7aced172000-08-15 01:13:23 +0000775 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000776 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000777 self.resetoutput()
778 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000779
780 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000781 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000782 self.executing = 0
783 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000784 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000785
786 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000787 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000788 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000789 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000790 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000791 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000792 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000793 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000794 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000795 return "cancel"
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000796 # interrupt the subprocess
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000797 self.canceled = True
798 if use_subprocess:
799 self.interp.interrupt_subprocess()
800 return "cancel"
801 else:
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000802 self.closing = True
803 # Wait for poll_subprocess() rescheduling to stop
804 self.text.after(2 * self.pollinterval, self.close2)
805
806 def close2(self):
807 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000808
809 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000810 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000811 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000812 if use_subprocess:
813 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000814 # Restore std streams
815 sys.stdout = self.save_stdout
816 sys.stderr = self.save_stderr
817 sys.stdin = self.save_stdin
818 # Break cycles
819 self.interp = None
820 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000821 self.flist.pyshell = None
822 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000823 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000824
825 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000826 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000827 return True
David Scherer7aced172000-08-15 01:13:23 +0000828
829 def short_title(self):
830 return self.shell_title
831
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000832 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000833 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000834
David Scherer7aced172000-08-15 01:13:23 +0000835 def begin(self):
836 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000837 if use_subprocess:
838 nosub = ''
839 else:
840 nosub = "==== No Subprocess ===="
841 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000842 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000843 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000844 self.showprompt()
845 import Tkinter
846 Tkinter._default_root = None
847
848 def interact(self):
849 self.begin()
850 self.top.mainloop()
851
852 def readline(self):
853 save = self.reading
854 try:
855 self.reading = 1
856 self.top.mainloop()
857 finally:
858 self.reading = save
859 line = self.text.get("iomark", "end-1c")
860 self.resetoutput()
861 if self.canceled:
862 self.canceled = 0
863 raise KeyboardInterrupt
864 if self.endoffile:
865 self.endoffile = 0
866 return ""
867 return line
868
869 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000870 return True
David Scherer7aced172000-08-15 01:13:23 +0000871
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000872 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000873 try:
874 if self.text.compare("sel.first", "!=", "sel.last"):
875 return # Active selection -- always use default binding
876 except:
877 pass
878 if not (self.executing or self.reading):
879 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000880 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000881 self.showprompt()
882 return "break"
883 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000884 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000885 if self.reading:
886 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000887 elif (self.executing and self.interp.rpcclt):
888 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000889 return "break"
890
891 def eof_callback(self, event):
892 if self.executing and not self.reading:
893 return # Let the default binding (delete next char) take over
894 if not (self.text.compare("iomark", "==", "insert") and
895 self.text.compare("insert", "==", "end-1c")):
896 return # Let the default binding (delete next char) take over
897 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000898 self.resetoutput()
899 self.close()
900 else:
901 self.canceled = 0
902 self.endoffile = 1
903 self.top.quit()
904 return "break"
905
906 def home_callback(self, event):
907 if event.state != 0 and event.keysym == "Home":
908 return # <Modifier-Home>; fall back to class binding
909 if self.text.compare("iomark", "<=", "insert") and \
910 self.text.compare("insert linestart", "<=", "iomark"):
911 self.text.mark_set("insert", "iomark")
912 self.text.tag_remove("sel", "1.0", "end")
913 self.text.see("insert")
914 return "break"
915
916 def linefeed_callback(self, event):
917 # Insert a linefeed without entering anything (still autoindented)
918 if self.reading:
919 self.text.insert("insert", "\n")
920 self.text.see("insert")
921 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000922 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000923 return "break"
924
925 def enter_callback(self, event):
926 if self.executing and not self.reading:
927 return # Let the default binding (insert '\n') take over
928 # If some text is selected, recall the selection
929 # (but only if this before the I/O mark)
930 try:
931 sel = self.text.get("sel.first", "sel.last")
932 if sel:
933 if self.text.compare("sel.last", "<=", "iomark"):
934 self.recall(sel)
935 return "break"
936 except:
937 pass
938 # If we're strictly before the line containing iomark, recall
939 # the current line, less a leading prompt, less leading or
940 # trailing whitespace
941 if self.text.compare("insert", "<", "iomark linestart"):
942 # Check if there's a relevant stdin range -- if so, use it
943 prev = self.text.tag_prevrange("stdin", "insert")
944 if prev and self.text.compare("insert", "<", prev[1]):
945 self.recall(self.text.get(prev[0], prev[1]))
946 return "break"
947 next = self.text.tag_nextrange("stdin", "insert")
948 if next and self.text.compare("insert lineend", ">=", next[0]):
949 self.recall(self.text.get(next[0], next[1]))
950 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000951 # No stdin mark -- just get the current line, less any prompt
952 line = self.text.get("insert linestart", "insert lineend")
953 last_line_of_prompt = sys.ps1.split('\n')[-1]
954 if line.startswith(last_line_of_prompt):
955 line = line[len(last_line_of_prompt):]
956 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000957 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000958 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000959 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000960 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000961 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000962 # If we're in the current input and there's only whitespace
963 # beyond the cursor, erase that whitespace first
964 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000965 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000966 self.text.delete("insert", "end-1c")
967 # If we're in the current input before its last line,
968 # insert a newline right at the insert point
969 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000970 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000971 return "break"
972 # We're in the last line; append a newline and submit it
973 self.text.mark_set("insert", "end-1c")
974 if self.reading:
975 self.text.insert("insert", "\n")
976 self.text.see("insert")
977 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000978 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000979 self.text.tag_add("stdin", "iomark", "end-1c")
980 self.text.update_idletasks()
981 if self.reading:
982 self.top.quit() # Break out of recursive mainloop() in raw_input()
983 else:
984 self.runit()
985 return "break"
986
987 def recall(self, s):
988 if self.history:
989 self.history.recall(s)
990
991 def runit(self):
992 line = self.text.get("iomark", "end-1c")
993 # Strip off last newline and surrounding whitespace.
994 # (To allow you to hit return twice to end a statement.)
995 i = len(line)
996 while i > 0 and line[i-1] in " \t":
997 i = i-1
998 if i > 0 and line[i-1] == "\n":
999 i = i-1
1000 while i > 0 and line[i-1] in " \t":
1001 i = i-1
1002 line = line[:i]
1003 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001004
David Scherer7aced172000-08-15 01:13:23 +00001005 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001006 if self.interp.rpcclt:
1007 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001008 try:
1009 sys.last_traceback
1010 except:
1011 tkMessageBox.showerror("No stack trace",
1012 "There is no stack trace yet.\n"
1013 "(sys.last_traceback is not defined)",
1014 master=self.text)
1015 return
1016 from StackViewer import StackBrowser
1017 sv = StackBrowser(self.root, self.flist)
1018
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001019 def view_restart_mark(self, event=None):
1020 self.text.see("iomark")
1021 self.text.see("restart")
1022
1023 def restart_shell(self, event=None):
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001024 if self.executing:
1025 self.cancel_callback()
1026 # Wait for subprocess to interrupt and restart
1027 # This can be a long time if shell is scrolling on a slow system
1028 # XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be
1029 # shorter if we didn't print the KeyboardInterrupt on
1030 # restarting while user code is running....
1031 self.text.after(2000, self.interp.restart_subprocess)
1032 else:
1033 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001034
David Scherer7aced172000-08-15 01:13:23 +00001035 def showprompt(self):
1036 self.resetoutput()
1037 try:
1038 s = str(sys.ps1)
1039 except:
1040 s = ""
1041 self.console.write(s)
1042 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001043 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001044 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001045
1046 def resetoutput(self):
1047 source = self.text.get("iomark", "end-1c")
1048 if self.history:
1049 self.history.history_store(source)
1050 if self.text.get("end-2c") != "\n":
1051 self.text.insert("end-1c", "\n")
1052 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001053 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001054 sys.stdout.softspace = 0
1055
1056 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001057 try:
1058 self.text.mark_gravity("iomark", "right")
1059 OutputWindow.write(self, s, tags, "iomark")
1060 self.text.mark_gravity("iomark", "left")
1061 except:
1062 pass
David Scherer7aced172000-08-15 01:13:23 +00001063 if self.canceled:
1064 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001065 if not use_subprocess:
1066 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001067
1068class PseudoFile:
1069
1070 def __init__(self, shell, tags):
1071 self.shell = shell
1072 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001073 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001074
1075 def write(self, s):
1076 self.shell.write(s, self.tags)
1077
1078 def writelines(self, l):
1079 map(self.write, l)
1080
1081 def flush(self):
1082 pass
1083
1084 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001085 return True
David Scherer7aced172000-08-15 01:13:23 +00001086
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001087
David Scherer7aced172000-08-15 01:13:23 +00001088usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001089
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001090USAGE: idle [-deins] [-t title] [file]*
1091 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1092 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001093
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001094 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001095 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001096
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001097The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001098
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001099 -e open an edit window
1100 -i open a shell window
1101
1102The following options imply -i and will open a shell:
1103
1104 -c cmd run the command in a shell, or
1105 -r file run script from file
1106
1107 -d enable the debugger
1108 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1109 -t title set title of shell window
1110
1111A default edit window will be bypassed when -c, -r, or - are used.
1112
1113[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1114
1115Examples:
1116
1117idle
1118 Open an edit window or shell depending on IDLE's configuration.
1119
1120idle foo.py foobar.py
1121 Edit the files, also open a shell if configured to start with shell.
1122
1123idle -est "Baz" foo.py
1124 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1125 window with the title "Baz".
1126
1127idle -c "import sys; print sys.argv" "foo"
1128 Open a shell window and run the command, passing "-c" in sys.argv[0]
1129 and "foo" in sys.argv[1].
1130
1131idle -d -s -r foo.py "Hello World"
1132 Open a shell window, run a startup script, enable the debugger, and
1133 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1134 sys.argv[1].
1135
1136echo "import sys; print sys.argv" | idle - "foobar"
1137 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1138 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001139"""
1140
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001141def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001142 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001143
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001144 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001145 enable_shell = False
1146 enable_edit = False
1147 debug = False
1148 cmd = None
1149 script = None
1150 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001151 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001152 sys.ps1
1153 except AttributeError:
1154 sys.ps1 = '>>> '
1155 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001156 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001157 except getopt.error, msg:
1158 sys.stderr.write("Error: %s\n" % str(msg))
1159 sys.stderr.write(usage_msg)
1160 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001161 for o, a in opts:
1162 if o == '-c':
1163 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001164 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001165 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001166 debug = True
1167 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001168 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001169 enable_edit = True
1170 if o == '-h':
1171 sys.stdout.write(usage_msg)
1172 sys.exit()
1173 if o == '-i':
1174 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001175 if o == '-n':
1176 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001177 if o == '-r':
1178 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001179 if os.path.isfile(script):
1180 pass
1181 else:
1182 print "No script file: ", script
1183 sys.exit()
1184 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001185 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001186 startup = True
1187 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001188 if o == '-t':
1189 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001190 enable_shell = True
1191 if args and args[0] == '-':
1192 cmd = sys.stdin.read()
1193 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001194 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001195 for i in range(len(sys.path)):
1196 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001197 if args and args[0] == '-':
1198 sys.argv = [''] + args[1:]
1199 elif cmd:
1200 sys.argv = ['-c'] + args
1201 elif script:
1202 sys.argv = [script] + args
1203 elif args:
1204 enable_edit = True
1205 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001206 for filename in args:
1207 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001208 for dir in pathx:
1209 dir = os.path.abspath(dir)
1210 if not dir in sys.path:
1211 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001212 else:
1213 dir = os.getcwd()
1214 if not dir in sys.path:
1215 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001216 # check the IDLE settings configuration (but command line overrides)
1217 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001218 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001219 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001220 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001221 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001222 root = Tk(className="Idle")
1223 fixwordbreaks(root)
1224 root.withdraw()
1225 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001226 if enable_edit:
1227 if not (cmd or script):
1228 for filename in args:
1229 flist.open(filename)
1230 if not args:
1231 flist.new()
1232 if enable_shell:
1233 flist.open_shell()
1234 elif enable_shell:
1235 flist.pyshell = PyShell(flist)
1236 flist.pyshell.begin()
1237 shell = flist.pyshell
1238 # handle remaining options:
1239 if debug:
1240 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001241 if startup:
1242 filename = os.environ.get("IDLESTARTUP") or \
1243 os.environ.get("PYTHONSTARTUP")
1244 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001245 shell.interp.execfile(filename)
1246 if cmd or script:
1247 shell.interp.runcommand("""if 1:
1248 import sys as _sys
1249 _sys.argv = %s
1250 del _sys
1251 \n""" % `sys.argv`)
1252 if cmd:
1253 shell.interp.execsource(cmd)
1254 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001255 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001256 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001257 root.mainloop()
1258 root.destroy()
1259
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001260
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001261def display_port_binding_error():
1262 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001263\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001264
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001265IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1266its Python execution server. IDLE is unable to bind to this port, and so
1267cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001268
1269 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001270 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001271 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001272
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001273Run IDLE with the -n command line switch to start without a subprocess
1274and refer to Help/IDLE Help "Running without a subprocess" for further
1275details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001276"""
David Scherer7aced172000-08-15 01:13:23 +00001277
1278if __name__ == "__main__":
1279 main()