1 """Shell is an interactive text control in which a user types in
2 commands to be sent to the interpreter. This particular shell is
3 based on wxPython's wxStyledTextCtrl.
5 Sponsored by Orbtech - Your source for Python programming expertise."""
7 __author__
= "Patrick K. O'Brien <pobrien@orbtech.com>"
9 __revision__
= "$Revision$"[11:-2]
19 from buffer import Buffer
23 from pseudo
import PseudoFileIn
24 from pseudo
import PseudoFileOut
25 from pseudo
import PseudoFileErr
26 from version
import VERSION
28 sys
.ps3
= '<-- ' # Input prompt.
30 NAVKEYS
= (wx
.WXK_END
, wx
.WXK_LEFT
, wx
.WXK_RIGHT
,
31 wx
.WXK_UP
, wx
.WXK_DOWN
, wx
.WXK_PRIOR
, wx
.WXK_NEXT
)
34 class ShellFrame(frame
.Frame
):
35 """Frame containing the shell component."""
38 revision
= __revision__
40 def __init__(self
, parent
=None, id=-1, title
='PyShell',
41 pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
42 style
=wx
.DEFAULT_FRAME_STYLE
, locals=None,
43 InterpClass
=None, *args
, **kwds
):
44 """Create ShellFrame instance."""
45 frame
.Frame
.__init
__(self
, parent
, id, title
, pos
, size
, style
)
46 intro
= 'PyShell %s - The Flakiest Python Shell' % VERSION
47 intro
+= '\nSponsored by Orbtech - ' + \
48 'Your source for Python programming expertise.'
49 self
.SetStatusText(intro
.replace('\n', ', '))
50 self
.shell
= Shell(parent
=self
, id=-1, introText
=intro
,
51 locals=locals, InterpClass
=InterpClass
,
53 # Override the shell so that status messages go to the status bar.
54 self
.shell
.setStatusText
= self
.SetStatusText
56 def OnClose(self
, event
):
57 """Event handler for closing."""
58 # This isn't working the way I want, but I'll leave it for now.
59 if self
.shell
.waiting
:
66 def OnAbout(self
, event
):
67 """Display an About window."""
68 title
= 'About PyShell'
69 text
= 'PyShell %s\n\n' % VERSION
+ \
70 'Yet another Python shell, only flakier.\n\n' + \
71 'Half-baked by Patrick K. O\'Brien,\n' + \
72 'the other half is still in the oven.\n\n' + \
73 'Shell Revision: %s\n' % self
.shell
.revision
+ \
74 'Interpreter Revision: %s\n\n' % self
.shell
.interp
.revision
+ \
75 'Python Version: %s\n' % sys
.version
.split()[0] + \
76 'wxPython Version: %s\n' % wx
.VERSION_STRING
+ \
77 'Platform: %s\n' % sys
.platform
78 dialog
= wx
.MessageDialog(self
, text
, title
,
79 wx
.OK | wx
.ICON_INFORMATION
)
85 """Simplified interface to all shell-related functionality.
87 This is a semi-transparent facade, in that all attributes of other
88 are accessible, even though only some are visible to the user."""
90 name
= 'Shell Interface'
91 revision
= __revision__
93 def __init__(self
, other
):
94 """Create a ShellFacade instance."""
100 Home Go to the beginning of the command or line.
101 Shift+Home Select to the beginning of the command or line.
102 Shift+End Select to the end of the line.
103 End Go to the end of the line.
104 Ctrl+C Copy selected text, removing prompts.
105 Ctrl+Shift+C Copy selected text, retaining prompts.
106 Ctrl+X Cut selected text.
107 Ctrl+V Paste from clipboard.
108 Ctrl+Shift+V Paste and run multiple commands from clipboard.
109 Ctrl+Up Arrow Retrieve Previous History item.
110 Alt+P Retrieve Previous History item.
111 Ctrl+Down Arrow Retrieve Next History item.
112 Alt+N Retrieve Next History item.
113 Shift+Up Arrow Insert Previous History item.
114 Shift+Down Arrow Insert Next History item.
115 F8 Command-completion of History item.
116 (Type a few characters of a previous command and press F8.)
117 Ctrl+Enter Insert new line into multiline command.
118 Ctrl+] Increase font size.
119 Ctrl+[ Decrease font size.
120 Ctrl+= Default font size.
124 """Display some useful information about how to use the shell."""
125 self
.write(self
.helpText
)
127 def __getattr__(self
, name
):
128 if hasattr(self
.other
, name
):
129 return getattr(self
.other
, name
)
131 raise AttributeError, name
133 def __setattr__(self
, name
, value
):
134 if self
.__dict
__.has_key(name
):
135 self
.__dict
__[name
] = value
136 elif hasattr(self
.other
, name
):
137 setattr(self
.other
, name
, value
)
139 raise AttributeError, name
141 def _getAttributeNames(self
):
142 """Return list of magic attributes to extend introspection."""
148 'autoCompleteAutoHide',
149 'autoCompleteCaseInsensitive',
150 'autoCompleteIncludeDouble',
151 'autoCompleteIncludeMagic',
152 'autoCompleteIncludeSingle',
169 class Shell(editwindow
.EditWindow
):
170 """Shell based on StyledTextCtrl."""
173 revision
= __revision__
175 def __init__(self
, parent
, id=-1, pos
=wx
.DefaultPosition
,
176 size
=wx
.DefaultSize
, style
=wx
.CLIP_CHILDREN
,
177 introText
='', locals=None, InterpClass
=None, *args
, **kwds
):
178 """Create Shell instance."""
179 editwindow
.EditWindow
.__init
__(self
, parent
, id, pos
, size
, style
)
183 locals = __main__
.__dict
__
184 # Grab these so they can be restored by self.redirect* methods.
185 self
.stdin
= sys
.stdin
186 self
.stdout
= sys
.stdout
187 self
.stderr
= sys
.stderr
188 # Import a default interpreter class if one isn't provided.
189 if InterpClass
== None:
190 from interpreter
import Interpreter
192 Interpreter
= InterpClass
193 # Create a replacement for stdin.
194 self
.reader
= PseudoFileIn(self
.readline
, self
.readlines
)
195 self
.reader
.input = ''
196 self
.reader
.isreading
= False
197 # Set up the interpreter.
198 self
.interp
= Interpreter(locals=locals,
199 rawin
=self
.raw_input,
201 stdout
=PseudoFileOut(self
.writeOut
),
202 stderr
=PseudoFileErr(self
.writeErr
),
205 self
.buffer = Buffer()
206 # Find out for which keycodes the interpreter will autocomplete.
207 self
.autoCompleteKeys
= self
.interp
.getAutoCompleteKeys()
208 # Keep track of the last non-continuation prompt positions.
209 self
.promptPosStart
= 0
210 self
.promptPosEnd
= 0
211 # Keep track of multi-line commands.
213 # Create the command history. Commands are added into the
214 # front of the list (ie. at index 0) as they are entered.
215 # self.historyIndex is the current position in the history; it
216 # gets incremented as you retrieve the previous command,
217 # decremented as you retrieve the next, and reset when you hit
218 # Enter. self.historyIndex == -1 means you're on the current
219 # command, not in the history.
221 self
.historyIndex
= -1
222 # Assign handlers for keyboard events.
223 wx
.EVT_CHAR(self
, self
.OnChar
)
224 wx
.EVT_KEY_DOWN(self
, self
.OnKeyDown
)
225 # Assign handler for idle time.
227 wx
.EVT_IDLE(self
, self
.OnIdle
)
228 # Display the introductory banner information.
229 self
.showIntro(introText
)
230 # Assign some pseudo keywords to the interpreter's namespace.
231 self
.setBuiltinKeywords()
232 # Add 'shell' to the interpreter's local namespace.
234 # Do this last so the user has complete control over their
235 # environment. They can override anything they want.
236 self
.execStartupScript(self
.interp
.startupScript
)
237 wx
.CallAfter(self
.ScrollToLine
, 0)
243 """Set focus to the shell."""
246 def OnIdle(self
, event
):
247 """Free the CPU to do other things."""
252 def showIntro(self
, text
=''):
253 """Display introductory text in the shell."""
255 if not text
.endswith(os
.linesep
):
259 self
.write(self
.interp
.introText
)
260 except AttributeError:
263 def setBuiltinKeywords(self
):
264 """Create pseudo keywords as part of builtins.
266 This sets `close`, `exit` and `quit` to a helpful string.
269 __builtin__
.close
= __builtin__
.exit
= __builtin__
.quit
= \
270 'Click on the close button to leave the application.'
273 """Quit the application."""
275 # XXX Good enough for now but later we want to send a close event.
277 # In the close event handler we can make sure they want to
278 # quit. Other applications, like PythonCard, may choose to
279 # hide rather than quit so we should just post the event and
280 # let the surrounding app decide what it wants to do.
281 self
.write('Click on the close button to leave the application.')
283 def setLocalShell(self
):
284 """Add 'shell' to locals as reference to ShellFacade instance."""
285 self
.interp
.locals['shell'] = ShellFacade(other
=self
)
287 def execStartupScript(self
, startupScript
):
288 """Execute the user's PYTHONSTARTUP script if they have one."""
289 if startupScript
and os
.path
.isfile(startupScript
):
290 text
= 'Startup script executed: ' + startupScript
291 self
.push('print %r; execfile(%r)' % (text
, startupScript
))
296 """Display information about Py."""
300 Py Shell Revision: %s
301 Py Interpreter Revision: %s
305 (__author__
, VERSION
, self
.revision
, self
.interp
.revision
,
306 sys
.version
.split()[0], wx
.VERSION_STRING
, sys
.platform
)
307 self
.write(text
.strip())
309 def OnChar(self
, event
):
310 """Keypress event handler.
312 Only receives an event if OnKeyDown calls event.Skip() for the
313 corresponding event."""
315 # Prevent modification of previously submitted
316 # commands/responses.
317 if not self
.CanEdit():
319 key
= event
.KeyCode()
320 currpos
= self
.GetCurrentPos()
321 stoppos
= self
.promptPosEnd
322 # Return (Enter) needs to be ignored in this handler.
323 if key
== wx
.WXK_RETURN
:
325 elif key
in self
.autoCompleteKeys
:
326 # Usually the dot (period) key activates auto completion.
327 # Get the command between the prompt and the cursor. Add
328 # the autocomplete character to the end of the command.
329 if self
.AutoCompActive():
330 self
.AutoCompCancel()
331 command
= self
.GetTextRange(stoppos
, currpos
) + chr(key
)
333 if self
.autoComplete
:
334 self
.autoCompleteShow(command
)
335 elif key
== ord('('):
336 # The left paren activates a call tip and cancels an
337 # active auto completion.
338 if self
.AutoCompActive():
339 self
.AutoCompCancel()
340 # Get the command between the prompt and the cursor. Add
341 # the '(' to the end of the command.
342 self
.ReplaceSelection('')
343 command
= self
.GetTextRange(stoppos
, currpos
) + '('
345 self
.autoCallTipShow(command
)
347 # Allow the normal event handling to take place.
350 def OnKeyDown(self
, event
):
351 """Key down event handler."""
353 key
= event
.KeyCode()
354 # If the auto-complete window is up let it do its thing.
355 if self
.AutoCompActive():
358 # Prevent modification of previously submitted
359 # commands/responses.
360 controlDown
= event
.ControlDown()
361 altDown
= event
.AltDown()
362 shiftDown
= event
.ShiftDown()
363 currpos
= self
.GetCurrentPos()
364 endpos
= self
.GetTextLength()
365 selecting
= self
.GetSelectionStart() != self
.GetSelectionEnd()
366 # Return (Enter) is used to submit a command to the
368 if not controlDown
and key
== wx
.WXK_RETURN
:
369 if self
.CallTipActive():
372 # Ctrl+Return (Cntrl+Enter) is used to insert a line break.
373 elif controlDown
and key
== wx
.WXK_RETURN
:
374 if self
.CallTipActive():
376 if currpos
== endpos
:
379 self
.insertLineBreak()
380 # Let Ctrl-Alt-* get handled normally.
381 elif controlDown
and altDown
:
383 # Clear the current, unexecuted command.
384 elif key
== wx
.WXK_ESCAPE
:
385 if self
.CallTipActive():
389 # Increase font size.
390 elif controlDown
and key
in (ord(']'),):
391 dispatcher
.send(signal
='FontIncrease')
392 # Decrease font size.
393 elif controlDown
and key
in (ord('['),):
394 dispatcher
.send(signal
='FontDecrease')
396 elif controlDown
and key
in (ord('='),):
397 dispatcher
.send(signal
='FontDefault')
398 # Cut to the clipboard.
399 elif (controlDown
and key
in (ord('X'), ord('x'))) \
400 or (shiftDown
and key
== wx
.WXK_DELETE
):
402 # Copy to the clipboard.
403 elif controlDown
and not shiftDown \
404 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
406 # Copy to the clipboard, including prompts.
407 elif controlDown
and shiftDown \
408 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
409 self
.CopyWithPrompts()
410 # Copy to the clipboard, including prefixed prompts.
411 elif altDown
and not controlDown \
412 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
413 self
.CopyWithPromptsPrefixed()
414 # Home needs to be aware of the prompt.
415 elif key
== wx
.WXK_HOME
:
416 home
= self
.promptPosEnd
418 self
.SetCurrentPos(home
)
419 if not selecting
and not shiftDown
:
421 self
.EnsureCaretVisible()
425 # The following handlers modify text, so we need to see if
426 # there is a selection that includes text prior to the prompt.
428 # Don't modify a selection with text prior to the prompt.
429 elif selecting
and key
not in NAVKEYS
and not self
.CanEdit():
431 # Paste from the clipboard.
432 elif (controlDown
and not shiftDown
and key
in (ord('V'), ord('v'))) \
433 or (shiftDown
and not controlDown
and key
== wx
.WXK_INSERT
):
435 # Paste from the clipboard, run commands.
436 elif controlDown
and shiftDown
and key
in (ord('V'), ord('v')):
438 # Replace with the previous command from the history buffer.
439 elif (controlDown
and key
== wx
.WXK_UP
) \
440 or (altDown
and key
in (ord('P'), ord('p'))):
441 self
.OnHistoryReplace(step
=+1)
442 # Replace with the next command from the history buffer.
443 elif (controlDown
and key
== wx
.WXK_DOWN
) \
444 or (altDown
and key
in (ord('N'), ord('n'))):
445 self
.OnHistoryReplace(step
=-1)
446 # Insert the previous command from the history buffer.
447 elif (shiftDown
and key
== wx
.WXK_UP
) and self
.CanEdit():
448 self
.OnHistoryInsert(step
=+1)
449 # Insert the next command from the history buffer.
450 elif (shiftDown
and key
== wx
.WXK_DOWN
) and self
.CanEdit():
451 self
.OnHistoryInsert(step
=-1)
452 # Search up the history for the text in front of the cursor.
453 elif key
== wx
.WXK_F8
:
454 self
.OnHistorySearch()
455 # Don't backspace over the latest non-continuation prompt.
456 elif key
== wx
.WXK_BACK
:
457 if selecting
and self
.CanEdit():
459 elif currpos
> self
.promptPosEnd
:
461 # Only allow these keys after the latest prompt.
462 elif key
in (wx
.WXK_TAB
, wx
.WXK_DELETE
):
465 # Don't toggle between insert mode and overwrite mode.
466 elif key
== wx
.WXK_INSERT
:
468 # Don't allow line deletion.
469 elif controlDown
and key
in (ord('L'), ord('l')):
471 # Don't allow line transposition.
472 elif controlDown
and key
in (ord('T'), ord('t')):
474 # Basic navigation keys should work anywhere.
477 # Protect the readonly portion of the shell.
478 elif not self
.CanEdit():
483 def clearCommand(self
):
484 """Delete the current, unexecuted command."""
485 startpos
= self
.promptPosEnd
486 endpos
= self
.GetTextLength()
487 self
.SetSelection(startpos
, endpos
)
488 self
.ReplaceSelection('')
491 def OnHistoryReplace(self
, step
):
492 """Replace with the previous/next command from the history buffer."""
494 self
.replaceFromHistory(step
)
496 def replaceFromHistory(self
, step
):
497 """Replace selection with command from the history buffer."""
499 self
.ReplaceSelection('')
500 newindex
= self
.historyIndex
+ step
501 if -1 <= newindex
<= len(self
.history
):
502 self
.historyIndex
= newindex
503 if 0 <= newindex
<= len(self
.history
)-1:
504 command
= self
.history
[self
.historyIndex
]
505 command
= command
.replace('\n', os
.linesep
+ ps2
)
506 self
.ReplaceSelection(command
)
508 def OnHistoryInsert(self
, step
):
509 """Insert the previous/next command from the history buffer."""
510 if not self
.CanEdit():
512 startpos
= self
.GetCurrentPos()
513 self
.replaceFromHistory(step
)
514 endpos
= self
.GetCurrentPos()
515 self
.SetSelection(endpos
, startpos
)
517 def OnHistorySearch(self
):
518 """Search up the history buffer for the text in front of the cursor."""
519 if not self
.CanEdit():
521 startpos
= self
.GetCurrentPos()
522 # The text up to the cursor is what we search for.
523 numCharsAfterCursor
= self
.GetTextLength() - startpos
524 searchText
= self
.getCommand(rstrip
=False)
525 if numCharsAfterCursor
> 0:
526 searchText
= searchText
[:-numCharsAfterCursor
]
529 # Search upwards from the current history position and loop
530 # back to the beginning if we don't find anything.
531 if (self
.historyIndex
<= -1) \
532 or (self
.historyIndex
>= len(self
.history
)-2):
533 searchOrder
= range(len(self
.history
))
535 searchOrder
= range(self
.historyIndex
+1, len(self
.history
)) + \
536 range(self
.historyIndex
)
537 for i
in searchOrder
:
538 command
= self
.history
[i
]
539 if command
[:len(searchText
)] == searchText
:
540 # Replace the current selection with the one we found.
541 self
.ReplaceSelection(command
[len(searchText
):])
542 endpos
= self
.GetCurrentPos()
543 self
.SetSelection(endpos
, startpos
)
544 # We've now warped into middle of the history.
545 self
.historyIndex
= i
548 def setStatusText(self
, text
):
549 """Display status information."""
551 # This method will likely be replaced by the enclosing app to
552 # do something more interesting, like write to a status bar.
555 def insertLineBreak(self
):
556 """Insert a new line break."""
558 self
.write(os
.linesep
)
562 def processLine(self
):
563 """Process the line of text at which the user hit Enter."""
565 # The user hit ENTER and we need to decide what to do. They
566 # could be sitting on any line in the shell.
568 thepos
= self
.GetCurrentPos()
569 startpos
= self
.promptPosEnd
570 endpos
= self
.GetTextLength()
572 # If they hit RETURN inside the current command, execute the
575 self
.SetCurrentPos(endpos
)
576 self
.interp
.more
= False
577 command
= self
.GetTextRange(startpos
, endpos
)
578 lines
= command
.split(os
.linesep
+ ps2
)
579 lines
= [line
.rstrip() for line
in lines
]
580 command
= '\n'.join(lines
)
581 if self
.reader
.isreading
:
583 # Match the behavior of the standard Python shell
584 # when the user hits return without entering a
587 self
.reader
.input = command
588 self
.write(os
.linesep
)
591 # Or replace the current command with the other command.
593 # If the line contains a command (even an invalid one).
594 if self
.getCommand(rstrip
=False):
595 command
= self
.getMultilineCommand()
598 # Otherwise, put the cursor back where we started.
600 self
.SetCurrentPos(thepos
)
601 self
.SetAnchor(thepos
)
603 def getMultilineCommand(self
, rstrip
=True):
604 """Extract a multi-line command from the editor.
606 The command may not necessarily be valid Python syntax."""
607 # XXX Need to extract real prompts here. Need to keep track of
608 # the prompt every time a command is issued.
613 # This is a total hack job, but it works.
614 text
= self
.GetCurLine()[0]
615 line
= self
.GetCurrentLine()
616 while text
[:ps2size
] == ps2
and line
> 0:
619 text
= self
.GetCurLine()[0]
620 if text
[:ps1size
] == ps1
:
621 line
= self
.GetCurrentLine()
623 startpos
= self
.GetCurrentPos() + ps1size
626 while self
.GetCurLine()[0][:ps2size
] == ps2
:
629 stoppos
= self
.GetCurrentPos()
630 command
= self
.GetTextRange(startpos
, stoppos
)
631 command
= command
.replace(os
.linesep
+ ps2
, '\n')
632 command
= command
.rstrip()
633 command
= command
.replace('\n', os
.linesep
+ ps2
)
637 command
= command
.rstrip()
640 def getCommand(self
, text
=None, rstrip
=True):
641 """Extract a command from text which may include a shell prompt.
643 The command may not necessarily be valid Python syntax."""
645 text
= self
.GetCurLine()[0]
646 # Strip the prompt off the front leaving just the command.
647 command
= self
.lstripPrompt(text
)
649 command
= '' # Real commands have prompts.
651 command
= command
.rstrip()
654 def lstripPrompt(self
, text
):
655 """Return text without a leading prompt."""
660 # Strip the prompt off the front of text.
661 if text
[:ps1size
] == ps1
:
662 text
= text
[ps1size
:]
663 elif text
[:ps2size
] == ps2
:
664 text
= text
[ps2size
:]
667 def push(self
, command
):
668 """Send command to the interpreter for execution."""
669 self
.write(os
.linesep
)
670 busy
= wx
.BusyCursor()
672 self
.more
= self
.interp
.push(command
)
676 self
.addHistory(command
.rstrip())
679 def addHistory(self
, command
):
680 """Add command to the command history."""
681 # Reset the history position.
682 self
.historyIndex
= -1
683 # Insert this command into the history, unless it's a blank
684 # line or the same as the last command.
686 and (len(self
.history
) == 0 or command
!= self
.history
[0]):
687 self
.history
.insert(0, command
)
689 def write(self
, text
):
690 """Display text in the shell.
692 Replace line endings with OS-specific endings."""
693 text
= self
.fixLineEndings(text
)
695 self
.EnsureCaretVisible()
697 def fixLineEndings(self
, text
):
698 """Return text with line endings replaced by OS-specific endings."""
699 lines
= text
.split('\r\n')
700 for l
in range(len(lines
)):
701 chunks
= lines
[l
].split('\r')
702 for c
in range(len(chunks
)):
703 chunks
[c
] = os
.linesep
.join(chunks
[c
].split('\n'))
704 lines
[l
] = os
.linesep
.join(chunks
)
705 text
= os
.linesep
.join(lines
)
709 """Display proper prompt for the context: ps1, ps2 or ps3.
711 If this is a continuation line, autoindent as necessary."""
712 isreading
= self
.reader
.isreading
715 prompt
= str(sys
.ps3
)
717 prompt
= str(sys
.ps2
)
719 prompt
= str(sys
.ps1
)
720 pos
= self
.GetCurLine()[1]
725 self
.write(os
.linesep
)
727 self
.promptPosStart
= self
.GetCurrentPos()
731 self
.promptPosEnd
= self
.GetCurrentPos()
732 # Keep the undo feature from undoing previous responses.
733 self
.EmptyUndoBuffer()
734 # XXX Add some autoindent magic here if more.
736 self
.write(' '*4) # Temporary hack indentation.
737 self
.EnsureCaretVisible()
738 self
.ScrollToColumn(0)
741 """Replacement for stdin.readline()."""
744 reader
.isreading
= True
747 while not reader
.input:
752 reader
.isreading
= False
753 input = str(input) # In case of Unicode.
757 """Replacement for stdin.readlines()."""
759 while lines
[-1:] != ['\n']:
760 lines
.append(self
.readline())
763 def raw_input(self
, prompt
=''):
764 """Return string based on user input."""
767 return self
.readline()
769 def ask(self
, prompt
='Please enter your response:'):
770 """Get response from the user using a dialog box."""
771 dialog
= wx
.TextEntryDialog(None, prompt
,
772 'Input Dialog (Raw)', '')
774 if dialog
.ShowModal() == wx
.ID_OK
:
775 text
= dialog
.GetValue()
782 """Halt execution pending a response from the user."""
783 self
.ask('Press enter to continue:')
786 """Delete all text from the shell."""
789 def run(self
, command
, prompt
=True, verbose
=True):
790 """Execute command as if it was typed in directly.
791 >>> shell.run('print "this"')
796 # Go to the very bottom of the text.
797 endpos
= self
.GetTextLength()
798 self
.SetCurrentPos(endpos
)
799 command
= command
.rstrip()
800 if prompt
: self
.prompt()
801 if verbose
: self
.write(command
)
804 def runfile(self
, filename
):
805 """Execute all commands in file as if they were typed into the
807 file = open(filename
)
810 for command
in file.readlines():
811 if command
[:6] == 'shell.':
812 # Run shell methods silently.
813 self
.run(command
, prompt
=False, verbose
=False)
815 self
.run(command
, prompt
=False, verbose
=True)
819 def autoCompleteShow(self
, command
):
820 """Display auto-completion popup list."""
821 self
.AutoCompSetAutoHide(self
.autoCompleteAutoHide
)
822 self
.AutoCompSetIgnoreCase(self
.autoCompleteCaseInsensitive
)
823 list = self
.interp
.getAutoCompleteList(command
,
824 includeMagic
=self
.autoCompleteIncludeMagic
,
825 includeSingle
=self
.autoCompleteIncludeSingle
,
826 includeDouble
=self
.autoCompleteIncludeDouble
)
828 options
= ' '.join(list)
830 self
.AutoCompShow(offset
, options
)
832 def autoCallTipShow(self
, command
):
833 """Display argument spec and docstring in a popup window."""
834 if self
.CallTipActive():
836 (name
, argspec
, tip
) = self
.interp
.getCallTip(command
)
838 dispatcher
.send(signal
='Shell.calltip', sender
=self
, calltip
=tip
)
839 if not self
.autoCallTip
:
842 startpos
= self
.GetCurrentPos()
843 self
.write(argspec
+ ')')
844 endpos
= self
.GetCurrentPos()
845 self
.SetSelection(endpos
, startpos
)
847 curpos
= self
.GetCurrentPos()
848 tippos
= curpos
- (len(name
) + 1)
849 fallback
= curpos
- self
.GetColumn(curpos
)
850 # In case there isn't enough room, only go back to the
852 tippos
= max(tippos
, fallback
)
853 self
.CallTipShow(tippos
, tip
)
855 def writeOut(self
, text
):
856 """Replacement for stdout."""
859 def writeErr(self
, text
):
860 """Replacement for stderr."""
863 def redirectStdin(self
, redirect
=True):
864 """If redirect is true then sys.stdin will come from the shell."""
866 sys
.stdin
= self
.reader
868 sys
.stdin
= self
.stdin
870 def redirectStdout(self
, redirect
=True):
871 """If redirect is true then sys.stdout will go to the shell."""
873 sys
.stdout
= PseudoFileOut(self
.writeOut
)
875 sys
.stdout
= self
.stdout
877 def redirectStderr(self
, redirect
=True):
878 """If redirect is true then sys.stderr will go to the shell."""
880 sys
.stderr
= PseudoFileErr(self
.writeErr
)
882 sys
.stderr
= self
.stderr
885 """Return true if text is selected and can be cut."""
886 if self
.GetSelectionStart() != self
.GetSelectionEnd() \
887 and self
.GetSelectionStart() >= self
.promptPosEnd \
888 and self
.GetSelectionEnd() >= self
.promptPosEnd
:
894 """Return true if a paste should succeed."""
895 if self
.CanEdit() and editwindow
.EditWindow
.CanPaste(self
):
901 """Return true if editing should succeed."""
902 if self
.GetSelectionStart() != self
.GetSelectionEnd():
903 if self
.GetSelectionStart() >= self
.promptPosEnd \
904 and self
.GetSelectionEnd() >= self
.promptPosEnd
:
909 return self
.GetCurrentPos() >= self
.promptPosEnd
912 """Remove selection and place it on the clipboard."""
913 if self
.CanCut() and self
.CanCopy():
914 if self
.AutoCompActive():
915 self
.AutoCompCancel()
916 if self
.CallTipActive():
919 self
.ReplaceSelection('')
922 """Copy selection and place it on the clipboard."""
926 command
= self
.GetSelectedText()
927 command
= command
.replace(os
.linesep
+ ps2
, os
.linesep
)
928 command
= command
.replace(os
.linesep
+ ps1
, os
.linesep
)
929 command
= self
.lstripPrompt(text
=command
)
930 data
= wx
.TextDataObject(command
)
933 def CopyWithPrompts(self
):
934 """Copy selection, including prompts, and place it on the clipboard."""
936 command
= self
.GetSelectedText()
937 data
= wx
.TextDataObject(command
)
940 def CopyWithPromptsPrefixed(self
):
941 """Copy selection, including prompts prefixed with four
942 spaces, and place it on the clipboard."""
944 command
= self
.GetSelectedText()
946 command
= spaces
+ command
.replace(os
.linesep
,
948 data
= wx
.TextDataObject(command
)
951 def _clip(self
, data
):
952 if wx
.TheClipboard
.Open():
953 wx
.TheClipboard
.UsePrimarySelection(False)
954 wx
.TheClipboard
.SetData(data
)
955 wx
.TheClipboard
.Flush()
956 wx
.TheClipboard
.Close()
959 """Replace selection with clipboard contents."""
960 if self
.CanPaste() and wx
.TheClipboard
.Open():
962 if wx
.TheClipboard
.IsSupported(wx
.DataFormat(wx
.DF_TEXT
)):
963 data
= wx
.TextDataObject()
964 if wx
.TheClipboard
.GetData(data
):
965 self
.ReplaceSelection('')
966 command
= data
.GetText()
967 command
= command
.rstrip()
968 command
= self
.fixLineEndings(command
)
969 command
= self
.lstripPrompt(text
=command
)
970 command
= command
.replace(os
.linesep
+ ps2
, '\n')
971 command
= command
.replace(os
.linesep
, '\n')
972 command
= command
.replace('\n', os
.linesep
+ ps2
)
974 wx
.TheClipboard
.Close()
976 def PasteAndRun(self
):
977 """Replace selection with clipboard contents, run commands."""
978 if wx
.TheClipboard
.Open():
981 if wx
.TheClipboard
.IsSupported(wx
.DataFormat(wx
.DF_TEXT
)):
982 data
= wx
.TextDataObject()
983 if wx
.TheClipboard
.GetData(data
):
984 endpos
= self
.GetTextLength()
985 self
.SetCurrentPos(endpos
)
986 startpos
= self
.promptPosEnd
987 self
.SetSelection(startpos
, endpos
)
988 self
.ReplaceSelection('')
989 text
= data
.GetText()
991 text
= self
.fixLineEndings(text
)
992 text
= self
.lstripPrompt(text
)
993 text
= text
.replace(os
.linesep
+ ps1
, '\n')
994 text
= text
.replace(os
.linesep
+ ps2
, '\n')
995 text
= text
.replace(os
.linesep
, '\n')
996 lines
= text
.split('\n')
1000 if line
.strip() == ps2
.strip():
1001 # If we are pasting from something like a
1002 # web page that drops the trailing space
1003 # from the ps2 prompt of a blank line.
1005 if line
.strip() != '' and line
.lstrip() == line
:
1008 # Add the previous command to the list.
1009 commands
.append(command
)
1010 # Start a new command, which may be multiline.
1013 # Multiline command. Add to the command.
1016 commands
.append(command
)
1017 for command
in commands
:
1018 command
= command
.replace('\n', os
.linesep
+ ps2
)
1021 wx
.TheClipboard
.Close()
1023 def wrap(self
, wrap
=True):
1024 """Sets whether text is word wrapped."""
1026 self
.SetWrapMode(wrap
)
1027 except AttributeError:
1028 return 'Wrapping is not available in this version.'
1030 def zoom(self
, points
=0):
1031 """Set the zoom level.
1033 This number of points is added to the size of all fonts. It
1034 may be positive to magnify or negative to reduce."""
1035 self
.SetZoom(points
)