blob: e2b545b4d42fb8f200f101180063b8b353aaa010 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
2
3# changes by dscherer@cmu.edu
4
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +00005# The main() function has been replaced by a whole class, in order to
David Scherer7aced172000-08-15 01:13:23 +00006# address the constraint that only one process can sit on the port
7# hard-coded into the loader.
8
9# It attempts to load the RPC protocol server and publish itself. If
10# that fails, it assumes that some other copy of IDLE is already running
11# on the port and attempts to contact it. It then uses the RPC mechanism
12# to ask that copy to do whatever it was instructed (via the command
13# line) to do. (Think netscape -remote). The handling of command line
14# arguments for remotes is still very incomplete.
15
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +000016# Default behavior (no command line options) is to open an editor window
17# instead of starting the Python Shell. However, if called as
18# Pyshell.main(0), the Shell will be started instead of the editor window.
David Scherer7aced172000-08-15 01:13:23 +000019
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +000020# In the default editor mode, if files are specified, they are opened.
21
22# If any command line options are specified, a shell does appear, and if
23# the -e option is used, both a shell and an editor window open.
David Scherer7aced172000-08-15 01:13:23 +000024
25import os
26import spawn
27import sys
28import string
29import getopt
30import re
31import protocol
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +000032import warnings
David Scherer7aced172000-08-15 01:13:23 +000033
34import linecache
35from code import InteractiveInterpreter
36
37from Tkinter import *
38import tkMessageBox
39
40from EditorWindow import EditorWindow, fixwordbreaks
41from FileList import FileList
42from ColorDelegator import ColorDelegator
43from UndoDelegator import UndoDelegator
44from OutputWindow import OutputWindow, OnDemandOutputWindow
45from IdleConf import idleconf
46import idlever
47
48# We need to patch linecache.checkcache, because we don't want it
49# to throw away our <pyshell#...> entries.
50# Rather than repeating its code here, we save those entries,
51# then call the original function, and then restore the saved entries.
52def linecache_checkcache(orig_checkcache=linecache.checkcache):
53 cache = linecache.cache
54 save = {}
55 for filename in cache.keys():
56 if filename[:1] + filename[-1:] == '<>':
57 save[filename] = cache[filename]
58 orig_checkcache()
59 cache.update(save)
60linecache.checkcache = linecache_checkcache
61
62
63# Note: <<newline-and-indent>> event is defined in AutoIndent.py
64
65#$ event <<plain-newline-and-indent>>
66#$ win <Control-j>
67#$ unix <Control-j>
68
69#$ event <<beginning-of-line>>
70#$ win <Control-a>
71#$ win <Home>
72#$ unix <Control-a>
73#$ unix <Home>
74
75#$ event <<history-next>>
76#$ win <Alt-n>
77#$ unix <Alt-n>
78
79#$ event <<history-previous>>
80#$ win <Alt-p>
81#$ unix <Alt-p>
82
83#$ event <<interrupt-execution>>
84#$ win <Control-c>
85#$ unix <Control-c>
86
87#$ event <<end-of-file>>
88#$ win <Control-d>
89#$ unix <Control-d>
90
91#$ event <<open-stack-viewer>>
92
93#$ event <<toggle-debugger>>
94
95
96class PyShellEditorWindow(EditorWindow):
97
98 # Regular text edit window when a shell is present
99 # XXX ought to merge with regular editor window
100
101 def __init__(self, *args):
102 apply(EditorWindow.__init__, (self,) + args)
103 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
104 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
105
106 rmenu_specs = [
107 ("Set breakpoint here", "<<set-breakpoint-here>>"),
108 ]
109
110 def set_breakpoint_here(self, event=None):
111 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
112 self.text.bell()
113 return
114 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
115
116
117class PyShellFileList(FileList):
118
119 # File list when a shell is present
120
121 EditorWindow = PyShellEditorWindow
122
123 pyshell = None
124
125 def open_shell(self, event=None):
126 if self.pyshell:
127 self.pyshell.wakeup()
128 else:
129 self.pyshell = PyShell(self)
130 self.pyshell.begin()
131 return self.pyshell
132
133
134class ModifiedColorDelegator(ColorDelegator):
135
136 # Colorizer for the shell window itself
137
138 def recolorize_main(self):
139 self.tag_remove("TODO", "1.0", "iomark")
140 self.tag_add("SYNC", "1.0", "iomark")
141 ColorDelegator.recolorize_main(self)
142
143 tagdefs = ColorDelegator.tagdefs.copy()
144 cconf = idleconf.getsection('Colors')
145
146 tagdefs.update({
147 "stdin": cconf.getcolor("stdin"),
148 "stdout": cconf.getcolor("stdout"),
149 "stderr": cconf.getcolor("stderr"),
150 "console": cconf.getcolor("console"),
151 "ERROR": cconf.getcolor("ERROR"),
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000152 None: cconf.getcolor("normal"),
David Scherer7aced172000-08-15 01:13:23 +0000153 })
154
155
156class ModifiedUndoDelegator(UndoDelegator):
157
158 # Forbid insert/delete before the I/O mark
159
160 def insert(self, index, chars, tags=None):
161 try:
162 if self.delegate.compare(index, "<", "iomark"):
163 self.delegate.bell()
164 return
165 except TclError:
166 pass
167 UndoDelegator.insert(self, index, chars, tags)
168
169 def delete(self, index1, index2=None):
170 try:
171 if self.delegate.compare(index1, "<", "iomark"):
172 self.delegate.bell()
173 return
174 except TclError:
175 pass
176 UndoDelegator.delete(self, index1, index2)
177
178class ModifiedInterpreter(InteractiveInterpreter):
179
180 def __init__(self, tkconsole):
181 self.tkconsole = tkconsole
182 locals = sys.modules['__main__'].__dict__
183 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000184 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000185
186 gid = 0
187
188 def execsource(self, source):
189 # Like runsource() but assumes complete exec source
190 filename = self.stuffsource(source)
191 self.execfile(filename, source)
192
193 def execfile(self, filename, source=None):
194 # Execute an existing file
195 if source is None:
196 source = open(filename, "r").read()
197 try:
198 code = compile(source, filename, "exec")
199 except (OverflowError, SyntaxError):
200 self.tkconsole.resetoutput()
201 InteractiveInterpreter.showsyntaxerror(self, filename)
202 else:
203 self.runcode(code)
204
205 def runsource(self, source):
206 # Extend base class to stuff the source in the line cache first
207 filename = self.stuffsource(source)
208 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000209 self.save_warnings_filters = warnings.filters[:]
210 warnings.filterwarnings(action="error", category=SyntaxWarning)
211 try:
212 return InteractiveInterpreter.runsource(self, source, filename)
213 finally:
214 if self.save_warnings_filters is not None:
215 warnings.filters[:] = self.save_warnings_filters
216 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000217
218 def stuffsource(self, source):
219 # Stuff source in the filename cache
220 filename = "<pyshell#%d>" % self.gid
221 self.gid = self.gid + 1
222 lines = string.split(source, "\n")
223 linecache.cache[filename] = len(source)+1, 0, lines, filename
224 return filename
225
226 def showsyntaxerror(self, filename=None):
227 # Extend base class to color the offending position
228 # (instead of printing it and pointing at it with a caret)
229 text = self.tkconsole.text
230 stuff = self.unpackerror()
231 if not stuff:
232 self.tkconsole.resetoutput()
233 InteractiveInterpreter.showsyntaxerror(self, filename)
234 return
235 msg, lineno, offset, line = stuff
236 if lineno == 1:
237 pos = "iomark + %d chars" % (offset-1)
238 else:
239 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
240 offset-1)
241 text.tag_add("ERROR", pos)
242 text.see(pos)
243 char = text.get(pos)
244 if char and char in string.letters + string.digits + "_":
245 text.tag_add("ERROR", pos + " wordstart", pos)
246 self.tkconsole.resetoutput()
247 self.write("SyntaxError: %s\n" % str(msg))
248
249 def unpackerror(self):
250 type, value, tb = sys.exc_info()
251 ok = type is SyntaxError
252 if ok:
253 try:
254 msg, (dummy_filename, lineno, offset, line) = value
255 except:
256 ok = 0
257 if ok:
258 return msg, lineno, offset, line
259 else:
260 return None
261
262 def showtraceback(self):
263 # Extend base class method to reset output properly
264 text = self.tkconsole.text
265 self.tkconsole.resetoutput()
266 self.checklinecache()
267 InteractiveInterpreter.showtraceback(self)
268
269 def checklinecache(self):
270 c = linecache.cache
271 for key in c.keys():
272 if key[:1] + key[-1:] != "<>":
273 del c[key]
274
275 debugger = None
276
277 def setdebugger(self, debugger):
278 self.debugger = debugger
279
280 def getdebugger(self):
281 return self.debugger
282
283 def runcode(self, code):
284 # Override base class method
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000285 if self.save_warnings_filters is not None:
286 warnings.filters[:] = self.save_warnings_filters
287 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000288 debugger = self.debugger
289 try:
290 self.tkconsole.beginexecuting()
291 try:
292 if debugger:
293 debugger.run(code, self.locals)
294 else:
295 exec code in self.locals
296 except SystemExit:
297 if tkMessageBox.askyesno(
298 "Exit?",
299 "Do you want to exit altogether?",
300 default="yes",
301 master=self.tkconsole.text):
302 raise
303 else:
304 self.showtraceback()
305 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
306 self.tkconsole.open_stack_viewer()
307 except:
308 self.showtraceback()
309 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
310 self.tkconsole.open_stack_viewer()
311
312 finally:
313 self.tkconsole.endexecuting()
314
315 def write(self, s):
316 # Override base class write
317 self.tkconsole.console.write(s)
318
319
320class PyShell(OutputWindow):
321
322 shell_title = "Python Shell"
323
324 # Override classes
325 ColorDelegator = ModifiedColorDelegator
326 UndoDelegator = ModifiedUndoDelegator
327
328 # Override menu bar specs
329 menu_specs = PyShellEditorWindow.menu_specs[:]
330 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
331
332 # New classes
333 from IdleHistory import History
334
335 def __init__(self, flist=None):
336 self.interp = ModifiedInterpreter(self)
337 if flist is None:
338 root = Tk()
339 fixwordbreaks(root)
340 root.withdraw()
341 flist = PyShellFileList(root)
342
343 OutputWindow.__init__(self, flist, None, None)
344
345 import __builtin__
346 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
347
348 self.auto = self.extensions["AutoIndent"] # Required extension
349 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
350
351 text = self.text
352 text.configure(wrap="char")
353 text.bind("<<newline-and-indent>>", self.enter_callback)
354 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
355 text.bind("<<interrupt-execution>>", self.cancel_callback)
356 text.bind("<<beginning-of-line>>", self.home_callback)
357 text.bind("<<end-of-file>>", self.eof_callback)
358 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
359 text.bind("<<toggle-debugger>>", self.toggle_debugger)
360 text.bind("<<open-python-shell>>", self.flist.open_shell)
361 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
362
363 self.save_stdout = sys.stdout
364 self.save_stderr = sys.stderr
365 self.save_stdin = sys.stdin
366 sys.stdout = PseudoFile(self, "stdout")
367 sys.stderr = PseudoFile(self, "stderr")
368 sys.stdin = self
369 self.console = PseudoFile(self, "console")
370
371 self.history = self.History(self.text)
372
373 reading = 0
374 executing = 0
375 canceled = 0
376 endoffile = 0
377
378 def toggle_debugger(self, event=None):
379 if self.executing:
380 tkMessageBox.showerror("Don't debug now",
381 "You can only toggle the debugger when idle",
382 master=self.text)
383 self.set_debugger_indicator()
384 return "break"
385 else:
386 db = self.interp.getdebugger()
387 if db:
388 self.close_debugger()
389 else:
390 self.open_debugger()
391
392 def set_debugger_indicator(self):
393 db = self.interp.getdebugger()
394 self.setvar("<<toggle-debugger>>", not not db)
395
396 def toggle_jit_stack_viewer( self, event=None):
397 pass # All we need is the variable
398
399 def close_debugger(self):
400 db = self.interp.getdebugger()
401 if db:
402 self.interp.setdebugger(None)
403 db.close()
404 self.resetoutput()
405 self.console.write("[DEBUG OFF]\n")
406 sys.ps1 = ">>> "
407 self.showprompt()
408 self.set_debugger_indicator()
409
410 def open_debugger(self):
411 import Debugger
412 self.interp.setdebugger(Debugger.Debugger(self))
413 sys.ps1 = "[DEBUG ON]\n>>> "
414 self.showprompt()
415 self.set_debugger_indicator()
416
417 def beginexecuting(self):
418 # Helper for ModifiedInterpreter
419 self.resetoutput()
420 self.executing = 1
421 ##self._cancel_check = self.cancel_check
422 ##sys.settrace(self._cancel_check)
423
424 def endexecuting(self):
425 # Helper for ModifiedInterpreter
426 ##sys.settrace(None)
427 ##self._cancel_check = None
428 self.executing = 0
429 self.canceled = 0
430
431 def close(self):
432 # Extend base class method
433 if self.executing:
434 # XXX Need to ask a question here
435 if not tkMessageBox.askokcancel(
436 "Kill?",
437 "The program is still running; do you want to kill it?",
438 default="ok",
439 master=self.text):
440 return "cancel"
441 self.canceled = 1
442 if self.reading:
443 self.top.quit()
444 return "cancel"
Kurt B. Kaiserbb6b1e92001-07-14 05:10:34 +0000445 return OutputWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000446
447 def _close(self):
448 self.close_debugger()
449 # Restore std streams
450 sys.stdout = self.save_stdout
451 sys.stderr = self.save_stderr
452 sys.stdin = self.save_stdin
453 # Break cycles
454 self.interp = None
455 self.console = None
456 self.auto = None
457 self.flist.pyshell = None
458 self.history = None
459 OutputWindow._close(self) # Really EditorWindow._close
460
461 def ispythonsource(self, filename):
462 # Override this so EditorWindow never removes the colorizer
463 return 1
464
465 def short_title(self):
466 return self.shell_title
467
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000468 COPYRIGHT = \
469 'Type "copyright", "credits" or "license" for more information.'
470
David Scherer7aced172000-08-15 01:13:23 +0000471 def begin(self):
472 self.resetoutput()
Kurt B. Kaisere75785a2001-07-16 05:25:12 +0000473 self.write("Python %s on %s\n%s\nIDLE Fork %s -- press F1 for help\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000474 (sys.version, sys.platform, self.COPYRIGHT,
David Scherer7aced172000-08-15 01:13:23 +0000475 idlever.IDLE_VERSION))
476 try:
477 sys.ps1
478 except AttributeError:
479 sys.ps1 = ">>> "
480 self.showprompt()
481 import Tkinter
482 Tkinter._default_root = None
483
484 def interact(self):
485 self.begin()
486 self.top.mainloop()
487
488 def readline(self):
489 save = self.reading
490 try:
491 self.reading = 1
492 self.top.mainloop()
493 finally:
494 self.reading = save
495 line = self.text.get("iomark", "end-1c")
496 self.resetoutput()
497 if self.canceled:
498 self.canceled = 0
499 raise KeyboardInterrupt
500 if self.endoffile:
501 self.endoffile = 0
502 return ""
503 return line
504
505 def isatty(self):
506 return 1
507
508 def cancel_callback(self, event):
509 try:
510 if self.text.compare("sel.first", "!=", "sel.last"):
511 return # Active selection -- always use default binding
512 except:
513 pass
514 if not (self.executing or self.reading):
515 self.resetoutput()
516 self.write("KeyboardInterrupt\n")
517 self.showprompt()
518 return "break"
519 self.endoffile = 0
520 self.canceled = 1
521 if self.reading:
522 self.top.quit()
523 return "break"
524
525 def eof_callback(self, event):
526 if self.executing and not self.reading:
527 return # Let the default binding (delete next char) take over
528 if not (self.text.compare("iomark", "==", "insert") and
529 self.text.compare("insert", "==", "end-1c")):
530 return # Let the default binding (delete next char) take over
531 if not self.executing:
532## if not tkMessageBox.askokcancel(
533## "Exit?",
534## "Are you sure you want to exit?",
535## default="ok", master=self.text):
536## return "break"
537 self.resetoutput()
538 self.close()
539 else:
540 self.canceled = 0
541 self.endoffile = 1
542 self.top.quit()
543 return "break"
544
545 def home_callback(self, event):
546 if event.state != 0 and event.keysym == "Home":
547 return # <Modifier-Home>; fall back to class binding
548 if self.text.compare("iomark", "<=", "insert") and \
549 self.text.compare("insert linestart", "<=", "iomark"):
550 self.text.mark_set("insert", "iomark")
551 self.text.tag_remove("sel", "1.0", "end")
552 self.text.see("insert")
553 return "break"
554
555 def linefeed_callback(self, event):
556 # Insert a linefeed without entering anything (still autoindented)
557 if self.reading:
558 self.text.insert("insert", "\n")
559 self.text.see("insert")
560 else:
561 self.auto.auto_indent(event)
562 return "break"
563
564 def enter_callback(self, event):
565 if self.executing and not self.reading:
566 return # Let the default binding (insert '\n') take over
567 # If some text is selected, recall the selection
568 # (but only if this before the I/O mark)
569 try:
570 sel = self.text.get("sel.first", "sel.last")
571 if sel:
572 if self.text.compare("sel.last", "<=", "iomark"):
573 self.recall(sel)
574 return "break"
575 except:
576 pass
577 # If we're strictly before the line containing iomark, recall
578 # the current line, less a leading prompt, less leading or
579 # trailing whitespace
580 if self.text.compare("insert", "<", "iomark linestart"):
581 # Check if there's a relevant stdin range -- if so, use it
582 prev = self.text.tag_prevrange("stdin", "insert")
583 if prev and self.text.compare("insert", "<", prev[1]):
584 self.recall(self.text.get(prev[0], prev[1]))
585 return "break"
586 next = self.text.tag_nextrange("stdin", "insert")
587 if next and self.text.compare("insert lineend", ">=", next[0]):
588 self.recall(self.text.get(next[0], next[1]))
589 return "break"
590 # No stdin mark -- just get the current line
591 self.recall(self.text.get("insert linestart", "insert lineend"))
592 return "break"
593 # If we're in the current input and there's only whitespace
594 # beyond the cursor, erase that whitespace first
595 s = self.text.get("insert", "end-1c")
596 if s and not string.strip(s):
597 self.text.delete("insert", "end-1c")
598 # If we're in the current input before its last line,
599 # insert a newline right at the insert point
600 if self.text.compare("insert", "<", "end-1c linestart"):
601 self.auto.auto_indent(event)
602 return "break"
603 # We're in the last line; append a newline and submit it
604 self.text.mark_set("insert", "end-1c")
605 if self.reading:
606 self.text.insert("insert", "\n")
607 self.text.see("insert")
608 else:
609 self.auto.auto_indent(event)
610 self.text.tag_add("stdin", "iomark", "end-1c")
611 self.text.update_idletasks()
612 if self.reading:
613 self.top.quit() # Break out of recursive mainloop() in raw_input()
614 else:
615 self.runit()
616 return "break"
617
618 def recall(self, s):
619 if self.history:
620 self.history.recall(s)
621
622 def runit(self):
623 line = self.text.get("iomark", "end-1c")
624 # Strip off last newline and surrounding whitespace.
625 # (To allow you to hit return twice to end a statement.)
626 i = len(line)
627 while i > 0 and line[i-1] in " \t":
628 i = i-1
629 if i > 0 and line[i-1] == "\n":
630 i = i-1
631 while i > 0 and line[i-1] in " \t":
632 i = i-1
633 line = line[:i]
634 more = self.interp.runsource(line)
635 if not more:
636 self.showprompt()
637
638 def cancel_check(self, frame, what, args,
639 dooneevent=tkinter.dooneevent,
640 dontwait=tkinter.DONT_WAIT):
641 # Hack -- use the debugger hooks to be able to handle events
642 # and interrupt execution at any time.
643 # This slows execution down quite a bit, so you may want to
644 # disable this (by not calling settrace() in runcode() above)
645 # for full-bore (uninterruptable) speed.
646 # XXX This should become a user option.
647 if self.canceled:
648 return
649 dooneevent(dontwait)
650 if self.canceled:
651 self.canceled = 0
652 raise KeyboardInterrupt
653 return self._cancel_check
654
655 def open_stack_viewer(self, event=None):
656 try:
657 sys.last_traceback
658 except:
659 tkMessageBox.showerror("No stack trace",
660 "There is no stack trace yet.\n"
661 "(sys.last_traceback is not defined)",
662 master=self.text)
663 return
664 from StackViewer import StackBrowser
665 sv = StackBrowser(self.root, self.flist)
666
667 def showprompt(self):
668 self.resetoutput()
669 try:
670 s = str(sys.ps1)
671 except:
672 s = ""
673 self.console.write(s)
674 self.text.mark_set("insert", "end-1c")
675
676 def resetoutput(self):
677 source = self.text.get("iomark", "end-1c")
678 if self.history:
679 self.history.history_store(source)
680 if self.text.get("end-2c") != "\n":
681 self.text.insert("end-1c", "\n")
682 self.text.mark_set("iomark", "end-1c")
683 sys.stdout.softspace = 0
684
685 def write(self, s, tags=()):
686 self.text.mark_gravity("iomark", "right")
687 OutputWindow.write(self, s, tags, "iomark")
688 self.text.mark_gravity("iomark", "left")
689 if self.canceled:
690 self.canceled = 0
691 raise KeyboardInterrupt
692
693class PseudoFile:
694
695 def __init__(self, shell, tags):
696 self.shell = shell
697 self.tags = tags
698
699 def write(self, s):
700 self.shell.write(s, self.tags)
701
702 def writelines(self, l):
703 map(self.write, l)
704
705 def flush(self):
706 pass
707
708 def isatty(self):
709 return 1
710
711usage_msg = """\
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000712usage: idle.py [-c command] [-d] [-i] [-r script] [-s] [-t title] [arg] ...
David Scherer7aced172000-08-15 01:13:23 +0000713
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000714idle file(s) (without options) edit the file(s)
David Scherer7aced172000-08-15 01:13:23 +0000715
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000716-c cmd run the command in a shell
717-d enable the debugger
718-i open an interactive shell
719-i file(s) open a shell and also an editor window for each file
720-r script run a file as a script in a shell
721-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
722-t title set title of shell window
723
724Remaining arguments are applied to the command (-c) or script (-r).
David Scherer7aced172000-08-15 01:13:23 +0000725"""
726
727class usageError:
728 def __init__(self, string): self.string = string
729 def __repr__(self): return self.string
730
731class main:
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +0000732 def __init__(self, noshell=1):
Steven M. Gava1f733ba2001-10-07 11:44:49 +0000733
734 global flist, root
735 root = Tk(className="Idle")
736 fixwordbreaks(root)
737 root.withdraw()
738 flist = PyShellFileList(root)
739
740 dbg=OnDemandOutputWindow(flist)
741 dbg.set_title('IDLE Debugging Messages')
742 sys.stdout = PseudoFile(dbg,['stdout'])
743 sys.stderr = PseudoFile(dbg,['stderr'])
744
David Scherer7aced172000-08-15 01:13:23 +0000745 try:
746 self.server = protocol.Server(connection_hook = self.address_ok)
747 protocol.publish( 'IDLE', self.connect )
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +0000748 self.main(sys.argv[1:], noshell)
David Scherer7aced172000-08-15 01:13:23 +0000749 return
750 except protocol.connectionLost:
751 try:
752 client = protocol.Client()
753 IDLE = client.getobject('IDLE')
754 if IDLE:
755 try:
756 IDLE.remote( sys.argv[1:] )
757 except usageError, msg:
758 sys.stderr.write("Error: %s\n" % str(msg))
759 sys.stderr.write(usage_msg)
760 return
761 except protocol.connectionLost:
762 pass
763
Steven M. Gava1f733ba2001-10-07 11:44:49 +0000764 #maybe the following should be handled by a tkmessagebox for
765 #users who don't start idle from a console??
766 print """\
767IDLE cannot run.
768
769IDLE needs to use a specific TCP/IP port (7454) in order to execute and
770debug programs. IDLE is unable to bind to this port, and so cannot
771start. Here are some possible causes of this problem:
772
773 1. TCP/IP networking is not installed or not working on this computer
774 2. Another program is running that uses this port
775 3. Another copy of IDLE stopped responding but is still bound to the port
776 4. Personal firewall software is preventing IDLE from using this port
777
778IDLE makes and accepts connections only with this computer, and does not
779communicate over the internet in any way. It's use of port 7454 should not
780be a security risk on a single-user machine.
781"""
782 dbg.owin.gotoline(1)
783 dbg.owin.remove_selection()
784 root.mainloop() # wait for user to read message
David Scherer7aced172000-08-15 01:13:23 +0000785
786 def idle(self):
787 spawn.kill_zombies()
788 self.server.rpc_loop()
789 root.after(25, self.idle)
790
791 # We permit connections from localhost only
792 def address_ok(self, addr):
793 return addr[0] == '127.0.0.1'
794
795 def connect(self, client, addr):
796 return self
797
798 def remote( self, argv ):
799 # xxx Should make this behavior match the behavior in main, or redo
800 # command line options entirely.
801
802 try:
803 opts, args = getopt.getopt(argv, "c:deist:")
804 except getopt.error, msg:
805 raise usageError(msg)
806
807 for filename in args:
808 flist.open(filename)
809 if not args:
810 flist.new()
811
Kurt B. Kaiser21ebb212001-07-16 04:00:10 +0000812 def main(self, argv, noshell):
David Scherer7aced172000-08-15 01:13:23 +0000813 cmd = None
814 edit = 0
David Scherer7aced172000-08-15 01:13:23 +0000815 debug = 0
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000816 interactive = 0
817 script = None
David Scherer7aced172000-08-15 01:13:23 +0000818 startup = 0
819
820 try:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000821 opts, args = getopt.getopt(argv, "c:dir:st:")
David Scherer7aced172000-08-15 01:13:23 +0000822 except getopt.error, msg:
823 sys.stderr.write("Error: %s\n" % str(msg))
824 sys.stderr.write(usage_msg)
825 sys.exit(2)
826
827 for o, a in opts:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000828 noshell = 0 # There are options, bring up a shell
David Scherer7aced172000-08-15 01:13:23 +0000829 if o == '-c':
830 cmd = a
831 if o == '-d':
832 debug = 1
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000833 if o == '-i':
834 interactive = 1
835 if o == '-r':
836 script = a
David Scherer7aced172000-08-15 01:13:23 +0000837 if o == '-s':
838 startup = 1
839 if o == '-t':
840 PyShell.shell_title = a
841
842 if noshell: edit=1
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000843 if interactive and args and args[0] != "-": edit = 1
David Scherer7aced172000-08-15 01:13:23 +0000844
David Scherer7aced172000-08-15 01:13:23 +0000845 for i in range(len(sys.path)):
846 sys.path[i] = os.path.abspath(sys.path[i])
847
848 pathx = []
849 if edit:
850 for filename in args:
851 pathx.append(os.path.dirname(filename))
852 elif args and args[0] != "-":
853 pathx.append(os.path.dirname(args[0]))
854 else:
855 pathx.append(os.curdir)
856 for dir in pathx:
857 dir = os.path.abspath(dir)
858 if not dir in sys.path:
859 sys.path.insert(0, dir)
860
David Scherer7aced172000-08-15 01:13:23 +0000861 if edit:
862 for filename in args:
863 flist.open(filename)
864 if not args:
865 flist.new()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000866 else:
867 if cmd:
868 sys.argv = ["-c"] + args
869 else:
870 sys.argv = args or [""]
871
David Scherer7aced172000-08-15 01:13:23 +0000872 if noshell:
873 flist.pyshell = None
874 else:
875 shell = PyShell(flist)
876 interp = shell.interp
877 flist.pyshell = shell
878
879 if startup:
880 filename = os.environ.get("IDLESTARTUP") or \
881 os.environ.get("PYTHONSTARTUP")
882 if filename and os.path.isfile(filename):
883 interp.execfile(filename)
884
885 if debug:
886 shell.open_debugger()
887 if cmd:
888 interp.execsource(cmd)
Kurt B. Kaiser96d88422001-07-17 04:59:01 +0000889 elif script:
890 if os.path.isfile(script):
891 interp.execfile(script)
892 else:
893 print "No script file: ", script
David Scherer7aced172000-08-15 01:13:23 +0000894 shell.begin()
895
896 self.idle()
897 root.mainloop()
898 root.destroy()
899
900
901if __name__ == "__main__":
902 main()