11 from code
import InteractiveInterpreter
16 from EditorWindow
import EditorWindow
, fixwordbreaks
17 from FileList
import FileList
18 from ColorDelegator
import ColorDelegator
19 from UndoDelegator
import UndoDelegator
20 from OutputWindow
import OutputWindow
21 from IdleConf
import idleconf
24 # We need to patch linecache.checkcache, because we don't want it
25 # to throw away our <pyshell#...> entries.
26 # Rather than repeating its code here, we save those entries,
27 # then call the original function, and then restore the saved entries.
28 def linecache_checkcache(orig_checkcache
=linecache
.checkcache
):
29 cache
= linecache
.cache
31 for filename
in cache
.keys():
32 if filename
[:1] + filename
[-1:] == '<>':
33 save
[filename
] = cache
[filename
]
36 linecache
.checkcache
= linecache_checkcache
39 # Note: <<newline-and-indent>> event is defined in AutoIndent.py
41 #$ event <<plain-newline-and-indent>>
45 #$ event <<beginning-of-line>>
51 #$ event <<history-next>>
55 #$ event <<history-previous>>
59 #$ event <<interrupt-execution>>
63 #$ event <<end-of-file>>
67 #$ event <<open-stack-viewer>>
69 #$ event <<toggle-debugger>>
72 class PyShellEditorWindow(EditorWindow
):
74 # Regular text edit window when a shell is present
75 # XXX ought to merge with regular editor window
77 def __init__(self
, *args
):
78 apply(EditorWindow
.__init
__, (self
,) + args
)
79 self
.text
.bind("<<set-breakpoint-here>>", self
.set_breakpoint_here
)
80 self
.text
.bind("<<open-python-shell>>", self
.flist
.open_shell
)
83 ("Set breakpoint here", "<<set-breakpoint-here>>"),
86 def set_breakpoint_here(self
, event
=None):
87 if not self
.flist
.pyshell
or not self
.flist
.pyshell
.interp
.debugger
:
90 self
.flist
.pyshell
.interp
.debugger
.set_breakpoint_here(self
)
93 class PyShellFileList(FileList
):
95 # File list when a shell is present
97 EditorWindow
= PyShellEditorWindow
101 def open_shell(self
, event
=None):
103 self
.pyshell
.wakeup()
105 self
.pyshell
= PyShell(self
)
110 class ModifiedColorDelegator(ColorDelegator
):
112 # Colorizer for the shell window itself
114 def recolorize_main(self
):
115 self
.tag_remove("TODO", "1.0", "iomark")
116 self
.tag_add("SYNC", "1.0", "iomark")
117 ColorDelegator
.recolorize_main(self
)
119 tagdefs
= ColorDelegator
.tagdefs
.copy()
120 cconf
= idleconf
.getsection('Colors')
123 "stdin": cconf
.getcolor("stdin"),
124 "stdout": cconf
.getcolor("stdout"),
125 "stderr": cconf
.getcolor("stderr"),
126 "console": cconf
.getcolor("console"),
127 "ERROR": cconf
.getcolor("ERROR"),
128 None: cconf
.getcolor("normal"),
132 class ModifiedUndoDelegator(UndoDelegator
):
134 # Forbid insert/delete before the I/O mark
136 def insert(self
, index
, chars
, tags
=None):
138 if self
.delegate
.compare(index
, "<", "iomark"):
143 UndoDelegator
.insert(self
, index
, chars
, tags
)
145 def delete(self
, index1
, index2
=None):
147 if self
.delegate
.compare(index1
, "<", "iomark"):
152 UndoDelegator
.delete(self
, index1
, index2
)
154 class ModifiedInterpreter(InteractiveInterpreter
):
156 def __init__(self
, tkconsole
):
157 self
.tkconsole
= tkconsole
158 locals = sys
.modules
['__main__'].__dict
__
159 InteractiveInterpreter
.__init
__(self
, locals=locals)
160 self
.save_warnings_filters
= None
164 def execsource(self
, source
):
165 # Like runsource() but assumes complete exec source
166 filename
= self
.stuffsource(source
)
167 self
.execfile(filename
, source
)
169 def execfile(self
, filename
, source
=None):
170 # Execute an existing file
172 source
= open(filename
, "r").read()
174 code
= compile(source
, filename
, "exec")
175 except (OverflowError, SyntaxError):
176 self
.tkconsole
.resetoutput()
177 InteractiveInterpreter
.showsyntaxerror(self
, filename
)
181 def runsource(self
, source
):
182 # Extend base class to stuff the source in the line cache first
183 filename
= self
.stuffsource(source
)
185 self
.save_warnings_filters
= warnings
.filters
[:]
186 warnings
.filterwarnings(action
="error", category
=SyntaxWarning)
188 return InteractiveInterpreter
.runsource(self
, source
, filename
)
190 if self
.save_warnings_filters
is not None:
191 warnings
.filters
[:] = self
.save_warnings_filters
192 self
.save_warnings_filters
= None
194 def stuffsource(self
, source
):
195 # Stuff source in the filename cache
196 filename
= "<pyshell#%d>" % self
.gid
197 self
.gid
= self
.gid
+ 1
198 lines
= string
.split(source
, "\n")
199 linecache
.cache
[filename
] = len(source
)+1, 0, lines
, filename
202 def showsyntaxerror(self
, filename
=None):
203 # Extend base class to color the offending position
204 # (instead of printing it and pointing at it with a caret)
205 text
= self
.tkconsole
.text
206 stuff
= self
.unpackerror()
208 self
.tkconsole
.resetoutput()
209 InteractiveInterpreter
.showsyntaxerror(self
, filename
)
211 msg
, lineno
, offset
, line
= stuff
213 pos
= "iomark + %d chars" % (offset
-1)
215 pos
= "iomark linestart + %d lines + %d chars" % (lineno
-1,
217 text
.tag_add("ERROR", pos
)
220 if char
and char
in string
.letters
+ string
.digits
+ "_":
221 text
.tag_add("ERROR", pos
+ " wordstart", pos
)
222 self
.tkconsole
.resetoutput()
223 self
.write("SyntaxError: %s\n" % str(msg
))
225 def unpackerror(self
):
226 type, value
, tb
= sys
.exc_info()
227 ok
= type is SyntaxError
230 msg
, (dummy_filename
, lineno
, offset
, line
) = value
234 return msg
, lineno
, offset
, line
238 def showtraceback(self
):
239 # Extend base class method to reset output properly
240 text
= self
.tkconsole
.text
241 self
.tkconsole
.resetoutput()
242 self
.checklinecache()
243 InteractiveInterpreter
.showtraceback(self
)
245 def checklinecache(self
):
248 if key
[:1] + key
[-1:] != "<>":
253 def setdebugger(self
, debugger
):
254 self
.debugger
= debugger
256 def getdebugger(self
):
259 def runcode(self
, code
):
260 # Override base class method
261 if self
.save_warnings_filters
is not None:
262 warnings
.filters
[:] = self
.save_warnings_filters
263 self
.save_warnings_filters
= None
264 debugger
= self
.debugger
266 self
.tkconsole
.beginexecuting()
269 debugger
.run(code
, self
.locals)
271 exec code
in self
.locals
273 if tkMessageBox
.askyesno(
275 "Do you want to exit altogether?",
277 master
=self
.tkconsole
.text
):
281 if self
.tkconsole
.getvar("<<toggle-jit-stack-viewer>>"):
282 self
.tkconsole
.open_stack_viewer()
285 if self
.tkconsole
.getvar("<<toggle-jit-stack-viewer>>"):
286 self
.tkconsole
.open_stack_viewer()
289 self
.tkconsole
.endexecuting()
292 # Override base class write
293 self
.tkconsole
.console
.write(s
)
296 class PyShell(OutputWindow
):
298 shell_title
= "Python Shell"
301 ColorDelegator
= ModifiedColorDelegator
302 UndoDelegator
= ModifiedUndoDelegator
304 # Override menu bar specs
305 menu_specs
= PyShellEditorWindow
.menu_specs
[:]
306 menu_specs
.insert(len(menu_specs
)-2, ("debug", "_Debug"))
309 from IdleHistory
import History
311 def __init__(self
, flist
=None):
312 self
.interp
= ModifiedInterpreter(self
)
317 flist
= PyShellFileList(root
)
319 OutputWindow
.__init
__(self
, flist
, None, None)
322 __builtin__
.quit
= __builtin__
.exit
= "To exit, type Ctrl-D."
324 self
.auto
= self
.extensions
["AutoIndent"] # Required extension
325 self
.auto
.config(usetabs
=1, indentwidth
=8, context_use_ps1
=1)
328 text
.configure(wrap
="char")
329 text
.bind("<<newline-and-indent>>", self
.enter_callback
)
330 text
.bind("<<plain-newline-and-indent>>", self
.linefeed_callback
)
331 text
.bind("<<interrupt-execution>>", self
.cancel_callback
)
332 text
.bind("<<beginning-of-line>>", self
.home_callback
)
333 text
.bind("<<end-of-file>>", self
.eof_callback
)
334 text
.bind("<<open-stack-viewer>>", self
.open_stack_viewer
)
335 text
.bind("<<toggle-debugger>>", self
.toggle_debugger
)
336 text
.bind("<<open-python-shell>>", self
.flist
.open_shell
)
337 text
.bind("<<toggle-jit-stack-viewer>>", self
.toggle_jit_stack_viewer
)
339 self
.save_stdout
= sys
.stdout
340 self
.save_stderr
= sys
.stderr
341 self
.save_stdin
= sys
.stdin
342 sys
.stdout
= PseudoFile(self
, "stdout")
343 sys
.stderr
= PseudoFile(self
, "stderr")
345 self
.console
= PseudoFile(self
, "console")
347 self
.history
= self
.History(self
.text
)
354 def toggle_debugger(self
, event
=None):
356 tkMessageBox
.showerror("Don't debug now",
357 "You can only toggle the debugger when idle",
359 self
.set_debugger_indicator()
362 db
= self
.interp
.getdebugger()
364 self
.close_debugger()
368 def set_debugger_indicator(self
):
369 db
= self
.interp
.getdebugger()
370 self
.setvar("<<toggle-debugger>>", not not db
)
372 def toggle_jit_stack_viewer( self
, event
=None):
373 pass # All we need is the variable
375 def close_debugger(self
):
376 db
= self
.interp
.getdebugger()
378 self
.interp
.setdebugger(None)
381 self
.console
.write("[DEBUG OFF]\n")
384 self
.set_debugger_indicator()
386 def open_debugger(self
):
388 self
.interp
.setdebugger(Debugger
.Debugger(self
))
389 sys
.ps1
= "[DEBUG ON]\n>>> "
391 self
.set_debugger_indicator()
393 def beginexecuting(self
):
394 # Helper for ModifiedInterpreter
397 ##self._cancel_check = self.cancel_check
398 ##sys.settrace(self._cancel_check)
400 def endexecuting(self
):
401 # Helper for ModifiedInterpreter
403 ##self._cancel_check = None
408 # Extend base class method
410 # XXX Need to ask a question here
411 if not tkMessageBox
.askokcancel(
413 "The program is still running; do you want to kill it?",
421 return OutputWindow
.close(self
)
424 self
.close_debugger()
425 # Restore std streams
426 sys
.stdout
= self
.save_stdout
427 sys
.stderr
= self
.save_stderr
428 sys
.stdin
= self
.save_stdin
433 self
.flist
.pyshell
= None
435 OutputWindow
._close
(self
) # Really EditorWindow._close
437 def ispythonsource(self
, filename
):
438 # Override this so EditorWindow never removes the colorizer
441 def short_title(self
):
442 return self
.shell_title
445 'Type "copyright", "credits" or "license" for more information.'
449 self
.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
450 (sys
.version
, sys
.platform
, self
.COPYRIGHT
,
451 idlever
.IDLE_VERSION
))
454 except AttributeError:
458 Tkinter
._default
_root
= None
471 line
= self
.text
.get("iomark", "end-1c")
475 raise KeyboardInterrupt
484 def cancel_callback(self
, event
):
486 if self
.text
.compare("sel.first", "!=", "sel.last"):
487 return # Active selection -- always use default binding
490 if not (self
.executing
or self
.reading
):
492 self
.write("KeyboardInterrupt\n")
501 def eof_callback(self
, event
):
502 if self
.executing
and not self
.reading
:
503 return # Let the default binding (delete next char) take over
504 if not (self
.text
.compare("iomark", "==", "insert") and
505 self
.text
.compare("insert", "==", "end-1c")):
506 return # Let the default binding (delete next char) take over
507 if not self
.executing
:
508 ## if not tkMessageBox.askokcancel(
510 ## "Are you sure you want to exit?",
511 ## default="ok", master=self.text):
521 def home_callback(self
, event
):
522 if event
.state
!= 0 and event
.keysym
== "Home":
523 return # <Modifier-Home>; fall back to class binding
524 if self
.text
.compare("iomark", "<=", "insert") and \
525 self
.text
.compare("insert linestart", "<=", "iomark"):
526 self
.text
.mark_set("insert", "iomark")
527 self
.text
.tag_remove("sel", "1.0", "end")
528 self
.text
.see("insert")
531 def linefeed_callback(self
, event
):
532 # Insert a linefeed without entering anything (still autoindented)
534 self
.text
.insert("insert", "\n")
535 self
.text
.see("insert")
537 self
.auto
.auto_indent(event
)
540 def enter_callback(self
, event
):
541 if self
.executing
and not self
.reading
:
542 return # Let the default binding (insert '\n') take over
543 # If some text is selected, recall the selection
544 # (but only if this before the I/O mark)
546 sel
= self
.text
.get("sel.first", "sel.last")
548 if self
.text
.compare("sel.last", "<=", "iomark"):
553 # If we're strictly before the line containing iomark, recall
554 # the current line, less a leading prompt, less leading or
555 # trailing whitespace
556 if self
.text
.compare("insert", "<", "iomark linestart"):
557 # Check if there's a relevant stdin range -- if so, use it
558 prev
= self
.text
.tag_prevrange("stdin", "insert")
559 if prev
and self
.text
.compare("insert", "<", prev
[1]):
560 self
.recall(self
.text
.get(prev
[0], prev
[1]))
562 next
= self
.text
.tag_nextrange("stdin", "insert")
563 if next
and self
.text
.compare("insert lineend", ">=", next
[0]):
564 self
.recall(self
.text
.get(next
[0], next
[1]))
566 # No stdin mark -- just get the current line
567 self
.recall(self
.text
.get("insert linestart", "insert lineend"))
569 # If we're in the current input and there's only whitespace
570 # beyond the cursor, erase that whitespace first
571 s
= self
.text
.get("insert", "end-1c")
572 if s
and not string
.strip(s
):
573 self
.text
.delete("insert", "end-1c")
574 # If we're in the current input before its last line,
575 # insert a newline right at the insert point
576 if self
.text
.compare("insert", "<", "end-1c linestart"):
577 self
.auto
.auto_indent(event
)
579 # We're in the last line; append a newline and submit it
580 self
.text
.mark_set("insert", "end-1c")
582 self
.text
.insert("insert", "\n")
583 self
.text
.see("insert")
585 self
.auto
.auto_indent(event
)
586 self
.text
.tag_add("stdin", "iomark", "end-1c")
587 self
.text
.update_idletasks()
589 self
.top
.quit() # Break out of recursive mainloop() in raw_input()
596 self
.history
.recall(s
)
599 line
= self
.text
.get("iomark", "end-1c")
600 # Strip off last newline and surrounding whitespace.
601 # (To allow you to hit return twice to end a statement.)
603 while i
> 0 and line
[i
-1] in " \t":
605 if i
> 0 and line
[i
-1] == "\n":
607 while i
> 0 and line
[i
-1] in " \t":
610 more
= self
.interp
.runsource(line
)
614 def cancel_check(self
, frame
, what
, args
,
615 dooneevent
=tkinter
.dooneevent
,
616 dontwait
=tkinter
.DONT_WAIT
):
617 # Hack -- use the debugger hooks to be able to handle events
618 # and interrupt execution at any time.
619 # This slows execution down quite a bit, so you may want to
620 # disable this (by not calling settrace() in runcode() above)
621 # for full-bore (uninterruptable) speed.
622 # XXX This should become a user option.
628 raise KeyboardInterrupt
629 return self
._cancel
_check
631 def open_stack_viewer(self
, event
=None):
635 tkMessageBox
.showerror("No stack trace",
636 "There is no stack trace yet.\n"
637 "(sys.last_traceback is not defined)",
640 from StackViewer
import StackBrowser
641 sv
= StackBrowser(self
.root
, self
.flist
)
643 def showprompt(self
):
649 self
.console
.write(s
)
650 self
.text
.mark_set("insert", "end-1c")
652 def resetoutput(self
):
653 source
= self
.text
.get("iomark", "end-1c")
655 self
.history
.history_store(source
)
656 if self
.text
.get("end-2c") != "\n":
657 self
.text
.insert("end-1c", "\n")
658 self
.text
.mark_set("iomark", "end-1c")
659 sys
.stdout
.softspace
= 0
661 def write(self
, s
, tags
=()):
662 self
.text
.mark_gravity("iomark", "right")
663 OutputWindow
.write(self
, s
, tags
, "iomark")
664 self
.text
.mark_gravity("iomark", "left")
667 raise KeyboardInterrupt
671 def __init__(self
, shell
, tags
):
676 self
.shell
.write(s
, self
.tags
)
678 def writelines(self
, l
):
689 usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
691 -c command run this command
693 -e edit mode; arguments are files to be edited
694 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
695 -t title set title of shell window
697 When neither -c nor -e is used, and there are arguments, and the first
698 argument is not '-', the first argument is run as a script. Remaining
699 arguments are arguments to the script or to the command run by -c.
709 opts
, args
= getopt
.getopt(sys
.argv
[1:], "c:deist:")
710 except getopt
.error
, msg
:
711 sys
.stderr
.write("Error: %s\n" % str(msg
))
712 sys
.stderr
.write(usage_msg
)
725 PyShell
.shell_title
= a
727 for i
in range(len(sys
.path
)):
728 sys
.path
[i
] = os
.path
.abspath(sys
.path
[i
])
732 for filename
in args
:
733 pathx
.append(os
.path
.dirname(filename
))
734 elif args
and args
[0] != "-":
735 pathx
.append(os
.path
.dirname(args
[0]))
737 pathx
.append(os
.curdir
)
739 dir = os
.path
.abspath(dir)
740 if not dir in sys
.path
:
741 sys
.path
.insert(0, dir)
744 root
= Tk(className
="Idle")
747 flist
= PyShellFileList(root
)
750 for filename
in args
:
754 sys
.argv
= ["-c"] + args
756 sys
.argv
= args
or [""]
759 shell
= PyShell(flist
)
760 interp
= shell
.interp
761 flist
.pyshell
= shell
764 filename
= os
.environ
.get("IDLESTARTUP") or \
765 os
.environ
.get("PYTHONSTARTUP")
766 if filename
and os
.path
.isfile(filename
):
767 interp
.execfile(filename
)
770 shell
.open_debugger()
772 interp
.execsource(cmd
)
773 elif not edit
and args
and args
[0] != "-":
774 interp
.execfile(args
[0])
781 if __name__
== "__main__":