blob: d978fc2138693ca972794866ed9af3800b6e82f7 [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
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 #
Chui Tey5d2af632002-05-26 13:36:41 +0000719 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000720 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000721
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000722 reading = False
723 executing = False
724 canceled = False
725 endoffile = False
726 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000727
728 def toggle_debugger(self, event=None):
729 if self.executing:
730 tkMessageBox.showerror("Don't debug now",
731 "You can only toggle the debugger when idle",
732 master=self.text)
733 self.set_debugger_indicator()
734 return "break"
735 else:
736 db = self.interp.getdebugger()
737 if db:
738 self.close_debugger()
739 else:
740 self.open_debugger()
741
742 def set_debugger_indicator(self):
743 db = self.interp.getdebugger()
744 self.setvar("<<toggle-debugger>>", not not db)
745
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000746 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000747 pass # All we need is the variable
748
749 def close_debugger(self):
750 db = self.interp.getdebugger()
751 if db:
752 self.interp.setdebugger(None)
753 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000754 if self.interp.rpcclt:
755 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000756 self.resetoutput()
757 self.console.write("[DEBUG OFF]\n")
758 sys.ps1 = ">>> "
759 self.showprompt()
760 self.set_debugger_indicator()
761
762 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000763 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000764 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
765 self)
766 else:
767 dbg_gui = Debugger.Debugger(self)
768 self.interp.setdebugger(dbg_gui)
769 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000770 sys.ps1 = "[DEBUG ON]\n>>> "
771 self.showprompt()
772 self.set_debugger_indicator()
773
David Scherer7aced172000-08-15 01:13:23 +0000774 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000775 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000776 self.resetoutput()
777 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000778
779 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000780 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000781 self.executing = 0
782 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000783 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000784
785 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000786 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000787 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000788 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000789 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000790 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000791 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000792 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000793 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000794 return "cancel"
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000795 # interrupt the subprocess
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000796 self.canceled = True
797 if use_subprocess:
798 self.interp.interrupt_subprocess()
799 return "cancel"
800 else:
801 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000802
803 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000804 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000805 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000806 if use_subprocess:
807 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000808 # Restore std streams
809 sys.stdout = self.save_stdout
810 sys.stderr = self.save_stderr
811 sys.stdin = self.save_stdin
812 # Break cycles
813 self.interp = None
814 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000815 self.flist.pyshell = None
816 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000817 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000818
819 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000820 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000821 return True
David Scherer7aced172000-08-15 01:13:23 +0000822
823 def short_title(self):
824 return self.shell_title
825
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000826 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000827 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000828
David Scherer7aced172000-08-15 01:13:23 +0000829 def begin(self):
830 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000831 if use_subprocess:
832 nosub = ''
833 else:
834 nosub = "==== No Subprocess ===="
835 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000836 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000837 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000838 self.showprompt()
839 import Tkinter
840 Tkinter._default_root = None
841
842 def interact(self):
843 self.begin()
844 self.top.mainloop()
845
846 def readline(self):
847 save = self.reading
848 try:
849 self.reading = 1
850 self.top.mainloop()
851 finally:
852 self.reading = save
853 line = self.text.get("iomark", "end-1c")
854 self.resetoutput()
855 if self.canceled:
856 self.canceled = 0
857 raise KeyboardInterrupt
858 if self.endoffile:
859 self.endoffile = 0
860 return ""
861 return line
862
863 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000864 return True
David Scherer7aced172000-08-15 01:13:23 +0000865
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000866 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000867 try:
868 if self.text.compare("sel.first", "!=", "sel.last"):
869 return # Active selection -- always use default binding
870 except:
871 pass
872 if not (self.executing or self.reading):
873 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000874 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000875 self.showprompt()
876 return "break"
877 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000878 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000879 if self.reading:
880 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000881 elif (self.executing and self.interp.rpcclt):
882 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000883 return "break"
884
885 def eof_callback(self, event):
886 if self.executing and not self.reading:
887 return # Let the default binding (delete next char) take over
888 if not (self.text.compare("iomark", "==", "insert") and
889 self.text.compare("insert", "==", "end-1c")):
890 return # Let the default binding (delete next char) take over
891 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000892 self.resetoutput()
893 self.close()
894 else:
895 self.canceled = 0
896 self.endoffile = 1
897 self.top.quit()
898 return "break"
899
900 def home_callback(self, event):
901 if event.state != 0 and event.keysym == "Home":
902 return # <Modifier-Home>; fall back to class binding
903 if self.text.compare("iomark", "<=", "insert") and \
904 self.text.compare("insert linestart", "<=", "iomark"):
905 self.text.mark_set("insert", "iomark")
906 self.text.tag_remove("sel", "1.0", "end")
907 self.text.see("insert")
908 return "break"
909
910 def linefeed_callback(self, event):
911 # Insert a linefeed without entering anything (still autoindented)
912 if self.reading:
913 self.text.insert("insert", "\n")
914 self.text.see("insert")
915 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000916 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000917 return "break"
918
919 def enter_callback(self, event):
920 if self.executing and not self.reading:
921 return # Let the default binding (insert '\n') take over
922 # If some text is selected, recall the selection
923 # (but only if this before the I/O mark)
924 try:
925 sel = self.text.get("sel.first", "sel.last")
926 if sel:
927 if self.text.compare("sel.last", "<=", "iomark"):
928 self.recall(sel)
929 return "break"
930 except:
931 pass
932 # If we're strictly before the line containing iomark, recall
933 # the current line, less a leading prompt, less leading or
934 # trailing whitespace
935 if self.text.compare("insert", "<", "iomark linestart"):
936 # Check if there's a relevant stdin range -- if so, use it
937 prev = self.text.tag_prevrange("stdin", "insert")
938 if prev and self.text.compare("insert", "<", prev[1]):
939 self.recall(self.text.get(prev[0], prev[1]))
940 return "break"
941 next = self.text.tag_nextrange("stdin", "insert")
942 if next and self.text.compare("insert lineend", ">=", next[0]):
943 self.recall(self.text.get(next[0], next[1]))
944 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000945 # No stdin mark -- just get the current line, less any prompt
946 line = self.text.get("insert linestart", "insert lineend")
947 last_line_of_prompt = sys.ps1.split('\n')[-1]
948 if line.startswith(last_line_of_prompt):
949 line = line[len(last_line_of_prompt):]
950 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000951 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000952 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000953 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000954 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000955 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000956 # If we're in the current input and there's only whitespace
957 # beyond the cursor, erase that whitespace first
958 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000959 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000960 self.text.delete("insert", "end-1c")
961 # If we're in the current input before its last line,
962 # insert a newline right at the insert point
963 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000964 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000965 return "break"
966 # We're in the last line; append a newline and submit it
967 self.text.mark_set("insert", "end-1c")
968 if self.reading:
969 self.text.insert("insert", "\n")
970 self.text.see("insert")
971 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000972 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000973 self.text.tag_add("stdin", "iomark", "end-1c")
974 self.text.update_idletasks()
975 if self.reading:
976 self.top.quit() # Break out of recursive mainloop() in raw_input()
977 else:
978 self.runit()
979 return "break"
980
981 def recall(self, s):
982 if self.history:
983 self.history.recall(s)
984
985 def runit(self):
986 line = self.text.get("iomark", "end-1c")
987 # Strip off last newline and surrounding whitespace.
988 # (To allow you to hit return twice to end a statement.)
989 i = len(line)
990 while i > 0 and line[i-1] in " \t":
991 i = i-1
992 if i > 0 and line[i-1] == "\n":
993 i = i-1
994 while i > 0 and line[i-1] in " \t":
995 i = i-1
996 line = line[:i]
997 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +0000998
David Scherer7aced172000-08-15 01:13:23 +0000999 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001000 if self.interp.rpcclt:
1001 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001002 try:
1003 sys.last_traceback
1004 except:
1005 tkMessageBox.showerror("No stack trace",
1006 "There is no stack trace yet.\n"
1007 "(sys.last_traceback is not defined)",
1008 master=self.text)
1009 return
1010 from StackViewer import StackBrowser
1011 sv = StackBrowser(self.root, self.flist)
1012
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001013 def view_restart_mark(self, event=None):
1014 self.text.see("iomark")
1015 self.text.see("restart")
1016
1017 def restart_shell(self, event=None):
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001018 if self.executing:
1019 self.cancel_callback()
1020 # Wait for subprocess to interrupt and restart
1021 # This can be a long time if shell is scrolling on a slow system
1022 # XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be
1023 # shorter if we didn't print the KeyboardInterrupt on
1024 # restarting while user code is running....
1025 self.text.after(2000, self.interp.restart_subprocess)
1026 else:
1027 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001028
David Scherer7aced172000-08-15 01:13:23 +00001029 def showprompt(self):
1030 self.resetoutput()
1031 try:
1032 s = str(sys.ps1)
1033 except:
1034 s = ""
1035 self.console.write(s)
1036 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001037 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001038 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001039
1040 def resetoutput(self):
1041 source = self.text.get("iomark", "end-1c")
1042 if self.history:
1043 self.history.history_store(source)
1044 if self.text.get("end-2c") != "\n":
1045 self.text.insert("end-1c", "\n")
1046 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001047 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001048 sys.stdout.softspace = 0
1049
1050 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001051 try:
1052 self.text.mark_gravity("iomark", "right")
1053 OutputWindow.write(self, s, tags, "iomark")
1054 self.text.mark_gravity("iomark", "left")
1055 except:
1056 pass
David Scherer7aced172000-08-15 01:13:23 +00001057 if self.canceled:
1058 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001059 if not use_subprocess:
1060 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001061
1062class PseudoFile:
1063
1064 def __init__(self, shell, tags):
1065 self.shell = shell
1066 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001067 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001068
1069 def write(self, s):
1070 self.shell.write(s, self.tags)
1071
1072 def writelines(self, l):
1073 map(self.write, l)
1074
1075 def flush(self):
1076 pass
1077
1078 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001079 return True
David Scherer7aced172000-08-15 01:13:23 +00001080
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001081
David Scherer7aced172000-08-15 01:13:23 +00001082usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001083
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001084USAGE: idle [-deins] [-t title] [file]*
1085 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1086 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001087
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001088 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001089 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001090
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001091The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001092
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001093 -e open an edit window
1094 -i open a shell window
1095
1096The following options imply -i and will open a shell:
1097
1098 -c cmd run the command in a shell, or
1099 -r file run script from file
1100
1101 -d enable the debugger
1102 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1103 -t title set title of shell window
1104
1105A default edit window will be bypassed when -c, -r, or - are used.
1106
1107[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1108
1109Examples:
1110
1111idle
1112 Open an edit window or shell depending on IDLE's configuration.
1113
1114idle foo.py foobar.py
1115 Edit the files, also open a shell if configured to start with shell.
1116
1117idle -est "Baz" foo.py
1118 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1119 window with the title "Baz".
1120
1121idle -c "import sys; print sys.argv" "foo"
1122 Open a shell window and run the command, passing "-c" in sys.argv[0]
1123 and "foo" in sys.argv[1].
1124
1125idle -d -s -r foo.py "Hello World"
1126 Open a shell window, run a startup script, enable the debugger, and
1127 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1128 sys.argv[1].
1129
1130echo "import sys; print sys.argv" | idle - "foobar"
1131 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1132 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001133"""
1134
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001135def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001136 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001137
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001138 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001139 enable_shell = False
1140 enable_edit = False
1141 debug = False
1142 cmd = None
1143 script = None
1144 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001145 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001146 sys.ps1
1147 except AttributeError:
1148 sys.ps1 = '>>> '
1149 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001150 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001151 except getopt.error, msg:
1152 sys.stderr.write("Error: %s\n" % str(msg))
1153 sys.stderr.write(usage_msg)
1154 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001155 for o, a in opts:
1156 if o == '-c':
1157 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001158 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001159 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001160 debug = True
1161 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001162 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001163 enable_edit = True
1164 if o == '-h':
1165 sys.stdout.write(usage_msg)
1166 sys.exit()
1167 if o == '-i':
1168 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001169 if o == '-n':
1170 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001171 if o == '-r':
1172 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001173 if os.path.isfile(script):
1174 pass
1175 else:
1176 print "No script file: ", script
1177 sys.exit()
1178 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001179 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001180 startup = True
1181 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001182 if o == '-t':
1183 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001184 enable_shell = True
1185 if args and args[0] == '-':
1186 cmd = sys.stdin.read()
1187 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001188 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001189 for i in range(len(sys.path)):
1190 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001191 if args and args[0] == '-':
1192 sys.argv = [''] + args[1:]
1193 elif cmd:
1194 sys.argv = ['-c'] + args
1195 elif script:
1196 sys.argv = [script] + args
1197 elif args:
1198 enable_edit = True
1199 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001200 for filename in args:
1201 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001202 for dir in pathx:
1203 dir = os.path.abspath(dir)
1204 if not dir in sys.path:
1205 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001206 else:
1207 dir = os.getcwd()
1208 if not dir in sys.path:
1209 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001210 # check the IDLE settings configuration (but command line overrides)
1211 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001212 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001213 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001214 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001215 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001216 root = Tk(className="Idle")
1217 fixwordbreaks(root)
1218 root.withdraw()
1219 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001220 if enable_edit:
1221 if not (cmd or script):
1222 for filename in args:
1223 flist.open(filename)
1224 if not args:
1225 flist.new()
1226 if enable_shell:
1227 flist.open_shell()
1228 elif enable_shell:
1229 flist.pyshell = PyShell(flist)
1230 flist.pyshell.begin()
1231 shell = flist.pyshell
1232 # handle remaining options:
1233 if debug:
1234 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001235 if startup:
1236 filename = os.environ.get("IDLESTARTUP") or \
1237 os.environ.get("PYTHONSTARTUP")
1238 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001239 shell.interp.execfile(filename)
1240 if cmd or script:
1241 shell.interp.runcommand("""if 1:
1242 import sys as _sys
1243 _sys.argv = %s
1244 del _sys
1245 \n""" % `sys.argv`)
1246 if cmd:
1247 shell.interp.execsource(cmd)
1248 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001249 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001250 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001251 root.mainloop()
1252 root.destroy()
1253
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001254
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001255def display_port_binding_error():
1256 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001257\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001258
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001259IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1260its Python execution server. IDLE is unable to bind to this port, and so
1261cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001262
1263 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001264 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001265 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001266
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001267Run IDLE with the -n command line switch to start without a subprocess
1268and refer to Help/IDLE Help "Running without a subprocess" for further
1269details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001270"""
David Scherer7aced172000-08-15 01:13:23 +00001271
1272if __name__ == "__main__":
1273 main()