blob: 5f9554a5a7758cbfc57485106dccf4d24d92b6d7 [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 if self.tkconsole.closing:
430 return
431 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000432 self.restart_subprocess()
433 self.tkconsole.endexecuting()
Chui Tey5d2af632002-05-26 13:36:41 +0000434 if response:
435 self.tkconsole.resetoutput()
436 self.active_seq = None
437 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000438 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000439 if how == "OK":
440 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000441 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000442 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000443 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
444 self.remote_stack_viewer()
445 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000446 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
447 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000448 print >>console, errmsg, what
449 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000450 self.tkconsole.endexecuting()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000451 # Reschedule myself in 50 ms
452 self.tkconsole.text.after(50, 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
David Scherer7aced172000-08-15 01:13:23 +0000529 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000530 """Extend base class method: Add Colorizing
531
532 Color the offending position instead of printing it and pointing at it
533 with a caret.
534
535 """
David Scherer7aced172000-08-15 01:13:23 +0000536 text = self.tkconsole.text
537 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000538 if stuff:
539 msg, lineno, offset, line = stuff
540 if lineno == 1:
541 pos = "iomark + %d chars" % (offset-1)
542 else:
543 pos = "iomark linestart + %d lines + %d chars" % \
544 (lineno-1, offset-1)
545 text.tag_add("ERROR", pos)
546 text.see(pos)
547 char = text.get(pos)
548 if char and char in IDENTCHARS:
549 text.tag_add("ERROR", pos + " wordstart", pos)
550 self.tkconsole.resetoutput()
551 self.write("SyntaxError: %s\n" % str(msg))
552 else:
David Scherer7aced172000-08-15 01:13:23 +0000553 self.tkconsole.resetoutput()
554 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000555 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000556
557 def unpackerror(self):
558 type, value, tb = sys.exc_info()
559 ok = type is SyntaxError
560 if ok:
561 try:
562 msg, (dummy_filename, lineno, offset, line) = value
563 except:
564 ok = 0
565 if ok:
566 return msg, lineno, offset, line
567 else:
568 return None
569
570 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000571 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000572 self.tkconsole.resetoutput()
573 self.checklinecache()
574 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000575 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
576 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000577
578 def checklinecache(self):
579 c = linecache.cache
580 for key in c.keys():
581 if key[:1] + key[-1:] != "<>":
582 del c[key]
583
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000584 def display_executing_dialog(self):
585 tkMessageBox.showerror(
586 "Already executing",
587 "The Python Shell window is already executing a command; "
588 "please wait until it is finished.",
589 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000590
Chui Tey5d2af632002-05-26 13:36:41 +0000591 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000592 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000593 # The code better not raise an exception!
594 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000595 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000596 return 0
597 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000598 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000599 else:
600 exec code in self.locals
601 return 1
602
David Scherer7aced172000-08-15 01:13:23 +0000603 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000604 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000605 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000606 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000607 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000608 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 debugger = self.debugger
612 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000613 self.tkconsole.beginexecuting()
614 try:
615 if not debugger and self.rpcclt is not None:
616 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
617 (code,), {})
618 elif debugger:
619 debugger.run(code, self.locals)
620 else:
621 exec code in self.locals
622 except SystemExit:
623 if tkMessageBox.askyesno(
624 "Exit?",
625 "Do you want to exit altogether?",
626 default="yes",
627 master=self.tkconsole.text):
628 raise
629 else:
630 self.showtraceback()
631 except:
David Scherer7aced172000-08-15 01:13:23 +0000632 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000633 finally:
634 if not use_subprocess:
635 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000636
637 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000638 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000639 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000640
David Scherer7aced172000-08-15 01:13:23 +0000641class PyShell(OutputWindow):
642
643 shell_title = "Python Shell"
644
645 # Override classes
646 ColorDelegator = ModifiedColorDelegator
647 UndoDelegator = ModifiedUndoDelegator
648
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000649 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000650 menu_specs = [
651 ("file", "_File"),
652 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000653 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000654 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000655 ("windows", "_Windows"),
656 ("help", "_Help"),
657 ]
David Scherer7aced172000-08-15 01:13:23 +0000658
659 # New classes
660 from IdleHistory import History
661
662 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000663 if use_subprocess:
664 self.menu_specs.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000665 self.interp = ModifiedInterpreter(self)
666 if flist is None:
667 root = Tk()
668 fixwordbreaks(root)
669 root.withdraw()
670 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000671 #
David Scherer7aced172000-08-15 01:13:23 +0000672 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000673 #
David Scherer7aced172000-08-15 01:13:23 +0000674 import __builtin__
675 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000676 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000677 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000678 #
David Scherer7aced172000-08-15 01:13:23 +0000679 text = self.text
680 text.configure(wrap="char")
681 text.bind("<<newline-and-indent>>", self.enter_callback)
682 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
683 text.bind("<<interrupt-execution>>", self.cancel_callback)
684 text.bind("<<beginning-of-line>>", self.home_callback)
685 text.bind("<<end-of-file>>", self.eof_callback)
686 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000687 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000688 text.bind("<<open-python-shell>>", self.flist.open_shell)
689 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000690 if use_subprocess:
691 text.bind("<<view-restart>>", self.view_restart_mark)
692 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000693 #
David Scherer7aced172000-08-15 01:13:23 +0000694 self.save_stdout = sys.stdout
695 self.save_stderr = sys.stderr
696 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000697 self.stdout = PseudoFile(self, "stdout")
698 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000699 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000700 if not use_subprocess:
701 sys.stdout = self.stdout
702 sys.stderr = self.stderr
703 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000704 #
David Scherer7aced172000-08-15 01:13:23 +0000705 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000706 #
Chui Tey5d2af632002-05-26 13:36:41 +0000707 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000708 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000709
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000710 reading = False
711 executing = False
712 canceled = False
713 endoffile = False
714 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000715
716 def toggle_debugger(self, event=None):
717 if self.executing:
718 tkMessageBox.showerror("Don't debug now",
719 "You can only toggle the debugger when idle",
720 master=self.text)
721 self.set_debugger_indicator()
722 return "break"
723 else:
724 db = self.interp.getdebugger()
725 if db:
726 self.close_debugger()
727 else:
728 self.open_debugger()
729
730 def set_debugger_indicator(self):
731 db = self.interp.getdebugger()
732 self.setvar("<<toggle-debugger>>", not not db)
733
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000734 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000735 pass # All we need is the variable
736
737 def close_debugger(self):
738 db = self.interp.getdebugger()
739 if db:
740 self.interp.setdebugger(None)
741 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000742 if self.interp.rpcclt:
743 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000744 self.resetoutput()
745 self.console.write("[DEBUG OFF]\n")
746 sys.ps1 = ">>> "
747 self.showprompt()
748 self.set_debugger_indicator()
749
750 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000751 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000752 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
753 self)
754 else:
755 dbg_gui = Debugger.Debugger(self)
756 self.interp.setdebugger(dbg_gui)
757 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000758 sys.ps1 = "[DEBUG ON]\n>>> "
759 self.showprompt()
760 self.set_debugger_indicator()
761
David Scherer7aced172000-08-15 01:13:23 +0000762 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000763 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000764 self.resetoutput()
765 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000766
767 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000768 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000769 self.executing = 0
770 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000771 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000772
773 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000774 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000775 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000776 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000777 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000778 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000779 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000780 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000781 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000782 return "cancel"
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000783 # interrupt the subprocess
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000784 self.canceled = True
785 if use_subprocess:
786 self.interp.interrupt_subprocess()
787 return "cancel"
788 else:
789 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000790
791 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000792 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000793 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000794 if use_subprocess:
795 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000796 # Restore std streams
797 sys.stdout = self.save_stdout
798 sys.stderr = self.save_stderr
799 sys.stdin = self.save_stdin
800 # Break cycles
801 self.interp = None
802 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000803 self.flist.pyshell = None
804 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000805 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000806
807 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000808 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000809 return True
David Scherer7aced172000-08-15 01:13:23 +0000810
811 def short_title(self):
812 return self.shell_title
813
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000814 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000815 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000816
David Scherer7aced172000-08-15 01:13:23 +0000817 def begin(self):
818 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000819 if use_subprocess:
820 nosub = ''
821 else:
822 nosub = "==== No Subprocess ===="
823 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000824 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000825 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000826 self.showprompt()
827 import Tkinter
828 Tkinter._default_root = None
829
830 def interact(self):
831 self.begin()
832 self.top.mainloop()
833
834 def readline(self):
835 save = self.reading
836 try:
837 self.reading = 1
838 self.top.mainloop()
839 finally:
840 self.reading = save
841 line = self.text.get("iomark", "end-1c")
842 self.resetoutput()
843 if self.canceled:
844 self.canceled = 0
845 raise KeyboardInterrupt
846 if self.endoffile:
847 self.endoffile = 0
848 return ""
849 return line
850
851 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000852 return True
David Scherer7aced172000-08-15 01:13:23 +0000853
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000854 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000855 try:
856 if self.text.compare("sel.first", "!=", "sel.last"):
857 return # Active selection -- always use default binding
858 except:
859 pass
860 if not (self.executing or self.reading):
861 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000862 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000863 self.showprompt()
864 return "break"
865 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000866 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000867 if self.reading:
868 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000869 elif (self.executing and self.interp.rpcclt):
870 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000871 return "break"
872
873 def eof_callback(self, event):
874 if self.executing and not self.reading:
875 return # Let the default binding (delete next char) take over
876 if not (self.text.compare("iomark", "==", "insert") and
877 self.text.compare("insert", "==", "end-1c")):
878 return # Let the default binding (delete next char) take over
879 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000880 self.resetoutput()
881 self.close()
882 else:
883 self.canceled = 0
884 self.endoffile = 1
885 self.top.quit()
886 return "break"
887
888 def home_callback(self, event):
889 if event.state != 0 and event.keysym == "Home":
890 return # <Modifier-Home>; fall back to class binding
891 if self.text.compare("iomark", "<=", "insert") and \
892 self.text.compare("insert linestart", "<=", "iomark"):
893 self.text.mark_set("insert", "iomark")
894 self.text.tag_remove("sel", "1.0", "end")
895 self.text.see("insert")
896 return "break"
897
898 def linefeed_callback(self, event):
899 # Insert a linefeed without entering anything (still autoindented)
900 if self.reading:
901 self.text.insert("insert", "\n")
902 self.text.see("insert")
903 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000904 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000905 return "break"
906
907 def enter_callback(self, event):
908 if self.executing and not self.reading:
909 return # Let the default binding (insert '\n') take over
910 # If some text is selected, recall the selection
911 # (but only if this before the I/O mark)
912 try:
913 sel = self.text.get("sel.first", "sel.last")
914 if sel:
915 if self.text.compare("sel.last", "<=", "iomark"):
916 self.recall(sel)
917 return "break"
918 except:
919 pass
920 # If we're strictly before the line containing iomark, recall
921 # the current line, less a leading prompt, less leading or
922 # trailing whitespace
923 if self.text.compare("insert", "<", "iomark linestart"):
924 # Check if there's a relevant stdin range -- if so, use it
925 prev = self.text.tag_prevrange("stdin", "insert")
926 if prev and self.text.compare("insert", "<", prev[1]):
927 self.recall(self.text.get(prev[0], prev[1]))
928 return "break"
929 next = self.text.tag_nextrange("stdin", "insert")
930 if next and self.text.compare("insert lineend", ">=", next[0]):
931 self.recall(self.text.get(next[0], next[1]))
932 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000933 # No stdin mark -- just get the current line, less any prompt
934 line = self.text.get("insert linestart", "insert lineend")
935 last_line_of_prompt = sys.ps1.split('\n')[-1]
936 if line.startswith(last_line_of_prompt):
937 line = line[len(last_line_of_prompt):]
938 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000939 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000940 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000941 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000942 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000943 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000944 # If we're in the current input and there's only whitespace
945 # beyond the cursor, erase that whitespace first
946 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000947 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000948 self.text.delete("insert", "end-1c")
949 # If we're in the current input before its last line,
950 # insert a newline right at the insert point
951 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000952 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000953 return "break"
954 # We're in the last line; append a newline and submit it
955 self.text.mark_set("insert", "end-1c")
956 if self.reading:
957 self.text.insert("insert", "\n")
958 self.text.see("insert")
959 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000960 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000961 self.text.tag_add("stdin", "iomark", "end-1c")
962 self.text.update_idletasks()
963 if self.reading:
964 self.top.quit() # Break out of recursive mainloop() in raw_input()
965 else:
966 self.runit()
967 return "break"
968
969 def recall(self, s):
970 if self.history:
971 self.history.recall(s)
972
973 def runit(self):
974 line = self.text.get("iomark", "end-1c")
975 # Strip off last newline and surrounding whitespace.
976 # (To allow you to hit return twice to end a statement.)
977 i = len(line)
978 while i > 0 and line[i-1] in " \t":
979 i = i-1
980 if i > 0 and line[i-1] == "\n":
981 i = i-1
982 while i > 0 and line[i-1] in " \t":
983 i = i-1
984 line = line[:i]
985 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +0000986
David Scherer7aced172000-08-15 01:13:23 +0000987 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +0000988 if self.interp.rpcclt:
989 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000990 try:
991 sys.last_traceback
992 except:
993 tkMessageBox.showerror("No stack trace",
994 "There is no stack trace yet.\n"
995 "(sys.last_traceback is not defined)",
996 master=self.text)
997 return
998 from StackViewer import StackBrowser
999 sv = StackBrowser(self.root, self.flist)
1000
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001001 def view_restart_mark(self, event=None):
1002 self.text.see("iomark")
1003 self.text.see("restart")
1004
1005 def restart_shell(self, event=None):
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001006 if self.executing:
1007 self.cancel_callback()
1008 # Wait for subprocess to interrupt and restart
1009 # This can be a long time if shell is scrolling on a slow system
1010 # XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be
1011 # shorter if we didn't print the KeyboardInterrupt on
1012 # restarting while user code is running....
1013 self.text.after(2000, self.interp.restart_subprocess)
1014 else:
1015 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001016
David Scherer7aced172000-08-15 01:13:23 +00001017 def showprompt(self):
1018 self.resetoutput()
1019 try:
1020 s = str(sys.ps1)
1021 except:
1022 s = ""
1023 self.console.write(s)
1024 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001025 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001026 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001027
1028 def resetoutput(self):
1029 source = self.text.get("iomark", "end-1c")
1030 if self.history:
1031 self.history.history_store(source)
1032 if self.text.get("end-2c") != "\n":
1033 self.text.insert("end-1c", "\n")
1034 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001035 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001036 sys.stdout.softspace = 0
1037
1038 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001039 try:
1040 self.text.mark_gravity("iomark", "right")
1041 OutputWindow.write(self, s, tags, "iomark")
1042 self.text.mark_gravity("iomark", "left")
1043 except:
1044 pass
David Scherer7aced172000-08-15 01:13:23 +00001045 if self.canceled:
1046 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001047 if not use_subprocess:
1048 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001049
1050class PseudoFile:
1051
1052 def __init__(self, shell, tags):
1053 self.shell = shell
1054 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001055 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001056
1057 def write(self, s):
1058 self.shell.write(s, self.tags)
1059
1060 def writelines(self, l):
1061 map(self.write, l)
1062
1063 def flush(self):
1064 pass
1065
1066 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001067 return True
David Scherer7aced172000-08-15 01:13:23 +00001068
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001069
David Scherer7aced172000-08-15 01:13:23 +00001070usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001071
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001072USAGE: idle [-deis] [-t title] [file]*
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001073 idle [-ds] [-t title] (-c cmd | -r file) [arg]*
1074 idle [-ds] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001075
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001076 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001077 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001078
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001079The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001080
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001081 -e open an edit window
1082 -i open a shell window
1083
1084The following options imply -i and will open a shell:
1085
1086 -c cmd run the command in a shell, or
1087 -r file run script from file
1088
1089 -d enable the debugger
1090 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1091 -t title set title of shell window
1092
1093A default edit window will be bypassed when -c, -r, or - are used.
1094
1095[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1096
1097Examples:
1098
1099idle
1100 Open an edit window or shell depending on IDLE's configuration.
1101
1102idle foo.py foobar.py
1103 Edit the files, also open a shell if configured to start with shell.
1104
1105idle -est "Baz" foo.py
1106 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1107 window with the title "Baz".
1108
1109idle -c "import sys; print sys.argv" "foo"
1110 Open a shell window and run the command, passing "-c" in sys.argv[0]
1111 and "foo" in sys.argv[1].
1112
1113idle -d -s -r foo.py "Hello World"
1114 Open a shell window, run a startup script, enable the debugger, and
1115 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1116 sys.argv[1].
1117
1118echo "import sys; print sys.argv" | idle - "foobar"
1119 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1120 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001121"""
1122
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001123def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001124 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001125
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001126 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001127 enable_shell = False
1128 enable_edit = False
1129 debug = False
1130 cmd = None
1131 script = None
1132 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001133 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001134 sys.ps1
1135 except AttributeError:
1136 sys.ps1 = '>>> '
1137 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001138 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001139 except getopt.error, msg:
1140 sys.stderr.write("Error: %s\n" % str(msg))
1141 sys.stderr.write(usage_msg)
1142 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001143 for o, a in opts:
1144 if o == '-c':
1145 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001146 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001147 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001148 debug = True
1149 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001150 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001151 enable_edit = True
1152 if o == '-h':
1153 sys.stdout.write(usage_msg)
1154 sys.exit()
1155 if o == '-i':
1156 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001157 if o == '-n':
1158 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001159 if o == '-r':
1160 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001161 if os.path.isfile(script):
1162 pass
1163 else:
1164 print "No script file: ", script
1165 sys.exit()
1166 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001167 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001168 startup = True
1169 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001170 if o == '-t':
1171 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001172 enable_shell = True
1173 if args and args[0] == '-':
1174 cmd = sys.stdin.read()
1175 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001176 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001177 for i in range(len(sys.path)):
1178 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001179 if args and args[0] == '-':
1180 sys.argv = [''] + args[1:]
1181 elif cmd:
1182 sys.argv = ['-c'] + args
1183 elif script:
1184 sys.argv = [script] + args
1185 elif args:
1186 enable_edit = True
1187 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001188 for filename in args:
1189 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001190 for dir in pathx:
1191 dir = os.path.abspath(dir)
1192 if not dir in sys.path:
1193 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001194 else:
1195 dir = os.getcwd()
1196 if not dir in sys.path:
1197 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001198 # check the IDLE settings configuration (but command line overrides)
1199 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001200 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001201 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001202 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001203 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001204 root = Tk(className="Idle")
1205 fixwordbreaks(root)
1206 root.withdraw()
1207 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001208 if enable_edit:
1209 if not (cmd or script):
1210 for filename in args:
1211 flist.open(filename)
1212 if not args:
1213 flist.new()
1214 if enable_shell:
1215 flist.open_shell()
1216 elif enable_shell:
1217 flist.pyshell = PyShell(flist)
1218 flist.pyshell.begin()
1219 shell = flist.pyshell
1220 # handle remaining options:
1221 if debug:
1222 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001223 if startup:
1224 filename = os.environ.get("IDLESTARTUP") or \
1225 os.environ.get("PYTHONSTARTUP")
1226 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001227 shell.interp.execfile(filename)
1228 if cmd or script:
1229 shell.interp.runcommand("""if 1:
1230 import sys as _sys
1231 _sys.argv = %s
1232 del _sys
1233 \n""" % `sys.argv`)
1234 if cmd:
1235 shell.interp.execsource(cmd)
1236 elif script:
1237 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001238 root.mainloop()
1239 root.destroy()
1240
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001241
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001242def display_port_binding_error():
1243 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001244\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001245
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001246IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1247its Python execution server. IDLE is unable to bind to this port, and so
1248cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001249
1250 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001251 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001252 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001253
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001254Run IDLE with the -n command line switch to start without a subprocess
1255and refer to Help/IDLE Help "Running without a subprocess" for further
1256details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001257"""
David Scherer7aced172000-08-15 01:13:23 +00001258
1259if __name__ == "__main__":
1260 main()