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
34 sys
.ps3
= '<-- ' # Input prompt.
36 NAVKEYS
= (wx
.WXK_END
, wx
.WXK_LEFT
, wx
.WXK_RIGHT
,
37 wx
.WXK_UP
, wx
.WXK_DOWN
, wx
.WXK_PRIOR
, wx
.WXK_NEXT
)
40 class ShellFrame(frame
.Frame
):
41 """Frame containing the shell component."""
44 revision
= __revision__
46 def __init__(self
, parent
=None, id=-1, title
='PyShell',
47 pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
48 style
=wx
.DEFAULT_FRAME_STYLE
, locals=None,
49 InterpClass
=None, *args
, **kwds
):
50 """Create ShellFrame instance."""
51 frame
.Frame
.__init
__(self
, parent
, id, title
, pos
, size
, style
)
52 intro
= 'PyShell %s - The Flakiest Python Shell' % VERSION
53 intro
+= '\nSponsored by Orbtech - ' + \
54 'Your source for Python programming expertise.'
55 self
.SetStatusText(intro
.replace('\n', ', '))
56 self
.shell
= Shell(parent
=self
, id=-1, introText
=intro
,
57 locals=locals, InterpClass
=InterpClass
,
59 # Override the shell so that status messages go to the status bar.
60 self
.shell
.setStatusText
= self
.SetStatusText
62 def OnClose(self
, event
):
63 """Event handler for closing."""
64 # This isn't working the way I want, but I'll leave it for now.
65 if self
.shell
.waiting
:
72 def OnAbout(self
, event
):
73 """Display an About window."""
74 title
= 'About PyShell'
75 text
= 'PyShell %s\n\n' % VERSION
+ \
76 'Yet another Python shell, only flakier.\n\n' + \
77 'Half-baked by Patrick K. O\'Brien,\n' + \
78 'the other half is still in the oven.\n\n' + \
79 'Shell Revision: %s\n' % self
.shell
.revision
+ \
80 'Interpreter Revision: %s\n\n' % self
.shell
.interp
.revision
+ \
81 'Python Version: %s\n' % sys
.version
.split()[0] + \
82 'wxPython Version: %s\n' % wx
.VERSION_STRING
+ \
83 'Platform: %s\n' % sys
.platform
84 dialog
= wx
.MessageDialog(self
, text
, title
,
85 wx
.OK | wx
.ICON_INFORMATION
)
91 """Simplified interface to all shell-related functionality.
93 This is a semi-transparent facade, in that all attributes of other
94 are accessible, even though only some are visible to the user."""
96 name
= 'Shell Interface'
97 revision
= __revision__
99 def __init__(self
, other
):
100 """Create a ShellFacade instance."""
106 Home Go to the beginning of the command or line.
107 Shift+Home Select to the beginning of the command or line.
108 Shift+End Select to the end of the line.
109 End Go to the end of the line.
110 Ctrl+C Copy selected text, removing prompts.
111 Ctrl+Shift+C Copy selected text, retaining prompts.
112 Ctrl+X Cut selected text.
113 Ctrl+V Paste from clipboard.
114 Ctrl+Shift+V Paste and run multiple commands from clipboard.
115 Ctrl+Up Arrow Retrieve Previous History item.
116 Alt+P Retrieve Previous History item.
117 Ctrl+Down Arrow Retrieve Next History item.
118 Alt+N Retrieve Next History item.
119 Shift+Up Arrow Insert Previous History item.
120 Shift+Down Arrow Insert Next History item.
121 F8 Command-completion of History item.
122 (Type a few characters of a previous command and press F8.)
123 Ctrl+Enter Insert new line into multiline command.
124 Ctrl+] Increase font size.
125 Ctrl+[ Decrease font size.
126 Ctrl+= Default font size.
130 """Display some useful information about how to use the shell."""
131 self
.write(self
.helpText
)
133 def __getattr__(self
, name
):
134 if hasattr(self
.other
, name
):
135 return getattr(self
.other
, name
)
137 raise AttributeError, name
139 def __setattr__(self
, name
, value
):
140 if self
.__dict
__.has_key(name
):
141 self
.__dict
__[name
] = value
142 elif hasattr(self
.other
, name
):
143 setattr(self
.other
, name
, value
)
145 raise AttributeError, name
147 def _getAttributeNames(self
):
148 """Return list of magic attributes to extend introspection."""
154 'autoCompleteCaseInsensitive',
155 'autoCompleteIncludeDouble',
156 'autoCompleteIncludeMagic',
157 'autoCompleteIncludeSingle',
174 class Shell(editwindow
.EditWindow
):
175 """Shell based on StyledTextCtrl."""
178 revision
= __revision__
180 def __init__(self
, parent
, id=-1, pos
=wx
.DefaultPosition
,
181 size
=wx
.DefaultSize
, style
=wx
.CLIP_CHILDREN
,
182 introText
='', locals=None, InterpClass
=None, *args
, **kwds
):
183 """Create Shell instance."""
184 editwindow
.EditWindow
.__init
__(self
, parent
, id, pos
, size
, style
)
188 # Grab these so they can be restored by self.redirect* methods.
189 self
.stdin
= sys
.stdin
190 self
.stdout
= sys
.stdout
191 self
.stderr
= sys
.stderr
192 # Import a default interpreter class if one isn't provided.
193 if InterpClass
== None:
194 from interpreter
import Interpreter
196 Interpreter
= InterpClass
197 # Create a replacement for stdin.
198 self
.reader
= PseudoFileIn(self
.readline
, self
.readlines
)
199 self
.reader
.input = ''
200 self
.reader
.isreading
= False
201 # Set up the interpreter.
202 self
.interp
= Interpreter(locals=locals,
203 rawin
=self
.raw_input,
205 stdout
=PseudoFileOut(self
.writeOut
),
206 stderr
=PseudoFileErr(self
.writeErr
),
209 self
.buffer = Buffer()
210 # Find out for which keycodes the interpreter will autocomplete.
211 self
.autoCompleteKeys
= self
.interp
.getAutoCompleteKeys()
212 # Keep track of the last non-continuation prompt positions.
213 self
.promptPosStart
= 0
214 self
.promptPosEnd
= 0
215 # Keep track of multi-line commands.
217 # Create the command history. Commands are added into the
218 # front of the list (ie. at index 0) as they are entered.
219 # self.historyIndex is the current position in the history; it
220 # gets incremented as you retrieve the previous command,
221 # decremented as you retrieve the next, and reset when you hit
222 # Enter. self.historyIndex == -1 means you're on the current
223 # command, not in the history.
225 self
.historyIndex
= -1
226 # Assign handlers for keyboard events.
227 wx
.EVT_CHAR(self
, self
.OnChar
)
228 wx
.EVT_KEY_DOWN(self
, self
.OnKeyDown
)
229 # Assign handler for idle time.
231 wx
.EVT_IDLE(self
, self
.OnIdle
)
232 # Display the introductory banner information.
233 self
.showIntro(introText
)
234 # Assign some pseudo keywords to the interpreter's namespace.
235 self
.setBuiltinKeywords()
236 # Add 'shell' to the interpreter's local namespace.
238 # Do this last so the user has complete control over their
239 # environment. They can override anything they want.
240 self
.execStartupScript(self
.interp
.startupScript
)
241 wx
.CallAfter(self
.ScrollToLine
, 0)
247 """Set focus to the shell."""
250 def OnIdle(self
, event
):
251 """Free the CPU to do other things."""
256 def showIntro(self
, text
=''):
257 """Display introductory text in the shell."""
259 if not text
.endswith(os
.linesep
):
263 self
.write(self
.interp
.introText
)
264 except AttributeError:
267 def setBuiltinKeywords(self
):
268 """Create pseudo keywords as part of builtins.
270 This sets `close`, `exit` and `quit` to a helpful string.
273 __builtin__
.close
= __builtin__
.exit
= __builtin__
.quit
= \
274 'Click on the close button to leave the application.'
277 """Quit the application."""
279 # XXX Good enough for now but later we want to send a close event.
281 # In the close event handler we can make sure they want to
282 # quit. Other applications, like PythonCard, may choose to
283 # hide rather than quit so we should just post the event and
284 # let the surrounding app decide what it wants to do.
285 self
.write('Click on the close button to leave the application.')
287 def setLocalShell(self
):
288 """Add 'shell' to locals as reference to ShellFacade instance."""
289 self
.interp
.locals['shell'] = ShellFacade(other
=self
)
291 def execStartupScript(self
, startupScript
):
292 """Execute the user's PYTHONSTARTUP script if they have one."""
293 if startupScript
and os
.path
.isfile(startupScript
):
294 text
= 'Startup script executed: ' + startupScript
295 self
.push('print %r; execfile(%r)' % (text
, startupScript
))
300 """Display information about Py."""
304 Py Shell Revision: %s
305 Py Interpreter Revision: %s
309 (__author__
, VERSION
, self
.revision
, self
.interp
.revision
,
310 sys
.version
.split()[0], wx
.VERSION_STRING
, sys
.platform
)
311 self
.write(text
.strip())
313 def OnChar(self
, event
):
314 """Keypress event handler.
316 Only receives an event if OnKeyDown calls event.Skip() for the
317 corresponding event."""
319 # Prevent modification of previously submitted
320 # commands/responses.
321 if not self
.CanEdit():
323 key
= event
.KeyCode()
324 currpos
= self
.GetCurrentPos()
325 stoppos
= self
.promptPosEnd
326 # Return (Enter) needs to be ignored in this handler.
327 if key
== wx
.WXK_RETURN
:
329 elif key
in self
.autoCompleteKeys
:
330 # Usually the dot (period) key activates auto completion.
331 # Get the command between the prompt and the cursor. Add
332 # the autocomplete character to the end of the command.
333 if self
.AutoCompActive():
334 self
.AutoCompCancel()
335 command
= self
.GetTextRange(stoppos
, currpos
) + chr(key
)
337 if self
.autoComplete
:
338 self
.autoCompleteShow(command
)
339 elif key
== ord('('):
340 # The left paren activates a call tip and cancels an
341 # active auto completion.
342 if self
.AutoCompActive():
343 self
.AutoCompCancel()
344 # Get the command between the prompt and the cursor. Add
345 # the '(' to the end of the command.
346 self
.ReplaceSelection('')
347 command
= self
.GetTextRange(stoppos
, currpos
) + '('
349 self
.autoCallTipShow(command
)
351 # Allow the normal event handling to take place.
354 def OnKeyDown(self
, event
):
355 """Key down event handler."""
357 key
= event
.KeyCode()
358 # If the auto-complete window is up let it do its thing.
359 if self
.AutoCompActive():
362 # Prevent modification of previously submitted
363 # commands/responses.
364 controlDown
= event
.ControlDown()
365 altDown
= event
.AltDown()
366 shiftDown
= event
.ShiftDown()
367 currpos
= self
.GetCurrentPos()
368 endpos
= self
.GetTextLength()
369 selecting
= self
.GetSelectionStart() != self
.GetSelectionEnd()
370 # Return (Enter) is used to submit a command to the
372 if not controlDown
and key
== wx
.WXK_RETURN
:
373 if self
.CallTipActive():
376 # Ctrl+Return (Cntrl+Enter) is used to insert a line break.
377 elif controlDown
and key
== wx
.WXK_RETURN
:
378 if self
.CallTipActive():
380 if currpos
== endpos
:
383 self
.insertLineBreak()
384 # Let Ctrl-Alt-* get handled normally.
385 elif controlDown
and altDown
:
387 # Clear the current, unexecuted command.
388 elif key
== wx
.WXK_ESCAPE
:
389 if self
.CallTipActive():
393 # Increase font size.
394 elif controlDown
and key
in (ord(']'),):
395 dispatcher
.send(signal
='FontIncrease')
396 # Decrease font size.
397 elif controlDown
and key
in (ord('['),):
398 dispatcher
.send(signal
='FontDecrease')
400 elif controlDown
and key
in (ord('='),):
401 dispatcher
.send(signal
='FontDefault')
402 # Cut to the clipboard.
403 elif (controlDown
and key
in (ord('X'), ord('x'))) \
404 or (shiftDown
and key
== wx
.WXK_DELETE
):
406 # Copy to the clipboard.
407 elif controlDown
and not shiftDown \
408 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
410 # Copy to the clipboard, including prompts.
411 elif controlDown
and shiftDown \
412 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
413 self
.CopyWithPrompts()
414 # Copy to the clipboard, including prefixed prompts.
415 elif altDown
and not controlDown \
416 and key
in (ord('C'), ord('c'), wx
.WXK_INSERT
):
417 self
.CopyWithPromptsPrefixed()
418 # Home needs to be aware of the prompt.
419 elif key
== wx
.WXK_HOME
:
420 home
= self
.promptPosEnd
422 self
.SetCurrentPos(home
)
423 if not selecting
and not shiftDown
:
425 self
.EnsureCaretVisible()
429 # The following handlers modify text, so we need to see if
430 # there is a selection that includes text prior to the prompt.
432 # Don't modify a selection with text prior to the prompt.
433 elif selecting
and key
not in NAVKEYS
and not self
.CanEdit():
435 # Paste from the clipboard.
436 elif (controlDown
and not shiftDown
and key
in (ord('V'), ord('v'))) \
437 or (shiftDown
and not controlDown
and key
== wx
.WXK_INSERT
):
439 # Paste from the clipboard, run commands.
440 elif controlDown
and shiftDown
and key
in (ord('V'), ord('v')):
442 # Replace with the previous command from the history buffer.
443 elif (controlDown
and key
== wx
.WXK_UP
) \
444 or (altDown
and key
in (ord('P'), ord('p'))):
445 self
.OnHistoryReplace(step
=+1)
446 # Replace with the next command from the history buffer.
447 elif (controlDown
and key
== wx
.WXK_DOWN
) \
448 or (altDown
and key
in (ord('N'), ord('n'))):
449 self
.OnHistoryReplace(step
=-1)
450 # Insert the previous command from the history buffer.
451 elif (shiftDown
and key
== wx
.WXK_UP
) and self
.CanEdit():
452 self
.OnHistoryInsert(step
=+1)
453 # Insert the next command from the history buffer.
454 elif (shiftDown
and key
== wx
.WXK_DOWN
) and self
.CanEdit():
455 self
.OnHistoryInsert(step
=-1)
456 # Search up the history for the text in front of the cursor.
457 elif key
== wx
.WXK_F8
:
458 self
.OnHistorySearch()
459 # Don't backspace over the latest non-continuation prompt.
460 elif key
== wx
.WXK_BACK
:
461 if selecting
and self
.CanEdit():
463 elif currpos
> self
.promptPosEnd
:
465 # Only allow these keys after the latest prompt.
466 elif key
in (wx
.WXK_TAB
, wx
.WXK_DELETE
):
469 # Don't toggle between insert mode and overwrite mode.
470 elif key
== wx
.WXK_INSERT
:
472 # Don't allow line deletion.
473 elif controlDown
and key
in (ord('L'), ord('l')):
475 # Don't allow line transposition.
476 elif controlDown
and key
in (ord('T'), ord('t')):
478 # Basic navigation keys should work anywhere.
481 # Protect the readonly portion of the shell.
482 elif not self
.CanEdit():
487 def clearCommand(self
):
488 """Delete the current, unexecuted command."""
489 startpos
= self
.promptPosEnd
490 endpos
= self
.GetTextLength()
491 self
.SetSelection(startpos
, endpos
)
492 self
.ReplaceSelection('')
495 def OnHistoryReplace(self
, step
):
496 """Replace with the previous/next command from the history buffer."""
498 self
.replaceFromHistory(step
)
500 def replaceFromHistory(self
, step
):
501 """Replace selection with command from the history buffer."""
503 self
.ReplaceSelection('')
504 newindex
= self
.historyIndex
+ step
505 if -1 <= newindex
<= len(self
.history
):
506 self
.historyIndex
= newindex
507 if 0 <= newindex
<= len(self
.history
)-1:
508 command
= self
.history
[self
.historyIndex
]
509 command
= command
.replace('\n', os
.linesep
+ ps2
)
510 self
.ReplaceSelection(command
)
512 def OnHistoryInsert(self
, step
):
513 """Insert the previous/next command from the history buffer."""
514 if not self
.CanEdit():
516 startpos
= self
.GetCurrentPos()
517 self
.replaceFromHistory(step
)
518 endpos
= self
.GetCurrentPos()
519 self
.SetSelection(endpos
, startpos
)
521 def OnHistorySearch(self
):
522 """Search up the history buffer for the text in front of the cursor."""
523 if not self
.CanEdit():
525 startpos
= self
.GetCurrentPos()
526 # The text up to the cursor is what we search for.
527 numCharsAfterCursor
= self
.GetTextLength() - startpos
528 searchText
= self
.getCommand(rstrip
=False)
529 if numCharsAfterCursor
> 0:
530 searchText
= searchText
[:-numCharsAfterCursor
]
533 # Search upwards from the current history position and loop
534 # back to the beginning if we don't find anything.
535 if (self
.historyIndex
<= -1) \
536 or (self
.historyIndex
>= len(self
.history
)-2):
537 searchOrder
= range(len(self
.history
))
539 searchOrder
= range(self
.historyIndex
+1, len(self
.history
)) + \
540 range(self
.historyIndex
)
541 for i
in searchOrder
:
542 command
= self
.history
[i
]
543 if command
[:len(searchText
)] == searchText
:
544 # Replace the current selection with the one we found.
545 self
.ReplaceSelection(command
[len(searchText
):])
546 endpos
= self
.GetCurrentPos()
547 self
.SetSelection(endpos
, startpos
)
548 # We've now warped into middle of the history.
549 self
.historyIndex
= i
552 def setStatusText(self
, text
):
553 """Display status information."""
555 # This method will likely be replaced by the enclosing app to
556 # do something more interesting, like write to a status bar.
559 def insertLineBreak(self
):
560 """Insert a new line break."""
562 self
.write(os
.linesep
)
566 def processLine(self
):
567 """Process the line of text at which the user hit Enter."""
569 # The user hit ENTER and we need to decide what to do. They
570 # could be sitting on any line in the shell.
572 thepos
= self
.GetCurrentPos()
573 startpos
= self
.promptPosEnd
574 endpos
= self
.GetTextLength()
576 # If they hit RETURN inside the current command, execute the
579 self
.SetCurrentPos(endpos
)
580 self
.interp
.more
= False
581 command
= self
.GetTextRange(startpos
, endpos
)
582 lines
= command
.split(os
.linesep
+ ps2
)
583 lines
= [line
.rstrip() for line
in lines
]
584 command
= '\n'.join(lines
)
585 if self
.reader
.isreading
:
587 # Match the behavior of the standard Python shell
588 # when the user hits return without entering a
591 self
.reader
.input = command
592 self
.write(os
.linesep
)
595 # Or replace the current command with the other command.
597 # If the line contains a command (even an invalid one).
598 if self
.getCommand(rstrip
=False):
599 command
= self
.getMultilineCommand()
602 # Otherwise, put the cursor back where we started.
604 self
.SetCurrentPos(thepos
)
605 self
.SetAnchor(thepos
)
607 def getMultilineCommand(self
, rstrip
=True):
608 """Extract a multi-line command from the editor.
610 The command may not necessarily be valid Python syntax."""
611 # XXX Need to extract real prompts here. Need to keep track of
612 # the prompt every time a command is issued.
617 # This is a total hack job, but it works.
618 text
= self
.GetCurLine()[0]
619 line
= self
.GetCurrentLine()
620 while text
[:ps2size
] == ps2
and line
> 0:
623 text
= self
.GetCurLine()[0]
624 if text
[:ps1size
] == ps1
:
625 line
= self
.GetCurrentLine()
627 startpos
= self
.GetCurrentPos() + ps1size
630 while self
.GetCurLine()[0][:ps2size
] == ps2
:
633 stoppos
= self
.GetCurrentPos()
634 command
= self
.GetTextRange(startpos
, stoppos
)
635 command
= command
.replace(os
.linesep
+ ps2
, '\n')
636 command
= command
.rstrip()
637 command
= command
.replace('\n', os
.linesep
+ ps2
)
641 command
= command
.rstrip()
644 def getCommand(self
, text
=None, rstrip
=True):
645 """Extract a command from text which may include a shell prompt.
647 The command may not necessarily be valid Python syntax."""
649 text
= self
.GetCurLine()[0]
650 # Strip the prompt off the front leaving just the command.
651 command
= self
.lstripPrompt(text
)
653 command
= '' # Real commands have prompts.
655 command
= command
.rstrip()
658 def lstripPrompt(self
, text
):
659 """Return text without a leading prompt."""
664 # Strip the prompt off the front of text.
665 if text
[:ps1size
] == ps1
:
666 text
= text
[ps1size
:]
667 elif text
[:ps2size
] == ps2
:
668 text
= text
[ps2size
:]
671 def push(self
, command
):
672 """Send command to the interpreter for execution."""
673 self
.write(os
.linesep
)
674 busy
= wx
.BusyCursor()
676 self
.more
= self
.interp
.push(command
)
680 self
.addHistory(command
.rstrip())
683 def addHistory(self
, command
):
684 """Add command to the command history."""
685 # Reset the history position.
686 self
.historyIndex
= -1
687 # Insert this command into the history, unless it's a blank
688 # line or the same as the last command.
690 and (len(self
.history
) == 0 or command
!= self
.history
[0]):
691 self
.history
.insert(0, command
)
693 def write(self
, text
):
694 """Display text in the shell.
696 Replace line endings with OS-specific endings."""
697 text
= self
.fixLineEndings(text
)
699 self
.EnsureCaretVisible()
701 def fixLineEndings(self
, text
):
702 """Return text with line endings replaced by OS-specific endings."""
703 lines
= text
.split('\r\n')
704 for l
in range(len(lines
)):
705 chunks
= lines
[l
].split('\r')
706 for c
in range(len(chunks
)):
707 chunks
[c
] = os
.linesep
.join(chunks
[c
].split('\n'))
708 lines
[l
] = os
.linesep
.join(chunks
)
709 text
= os
.linesep
.join(lines
)
713 """Display proper prompt for the context: ps1, ps2 or ps3.
715 If this is a continuation line, autoindent as necessary."""
716 isreading
= self
.reader
.isreading
719 prompt
= str(sys
.ps3
)
721 prompt
= str(sys
.ps2
)
723 prompt
= str(sys
.ps1
)
724 pos
= self
.GetCurLine()[1]
729 self
.write(os
.linesep
)
731 self
.promptPosStart
= self
.GetCurrentPos()
735 self
.promptPosEnd
= self
.GetCurrentPos()
736 # Keep the undo feature from undoing previous responses.
737 self
.EmptyUndoBuffer()
738 # XXX Add some autoindent magic here if more.
740 self
.write(' '*4) # Temporary hack indentation.
741 self
.EnsureCaretVisible()
742 self
.ScrollToColumn(0)
745 """Replacement for stdin.readline()."""
748 reader
.isreading
= True
751 while not reader
.input:
756 reader
.isreading
= False
757 input = str(input) # In case of Unicode.
761 """Replacement for stdin.readlines()."""
763 while lines
[-1:] != ['\n']:
764 lines
.append(self
.readline())
767 def raw_input(self
, prompt
=''):
768 """Return string based on user input."""
771 return self
.readline()
773 def ask(self
, prompt
='Please enter your response:'):
774 """Get response from the user using a dialog box."""
775 dialog
= wx
.TextEntryDialog(None, prompt
,
776 'Input Dialog (Raw)', '')
778 if dialog
.ShowModal() == wx
.ID_OK
:
779 text
= dialog
.GetValue()
786 """Halt execution pending a response from the user."""
787 self
.ask('Press enter to continue:')
790 """Delete all text from the shell."""
793 def run(self
, command
, prompt
=True, verbose
=True):
794 """Execute command as if it was typed in directly.
795 >>> shell.run('print "this"')
800 # Go to the very bottom of the text.
801 endpos
= self
.GetTextLength()
802 self
.SetCurrentPos(endpos
)
803 command
= command
.rstrip()
804 if prompt
: self
.prompt()
805 if verbose
: self
.write(command
)
808 def runfile(self
, filename
):
809 """Execute all commands in file as if they were typed into the
811 file = open(filename
)
814 for command
in file.readlines():
815 if command
[:6] == 'shell.':
816 # Run shell methods silently.
817 self
.run(command
, prompt
=False, verbose
=False)
819 self
.run(command
, prompt
=False, verbose
=True)
823 def autoCompleteShow(self
, command
):
824 """Display auto-completion popup list."""
825 list = self
.interp
.getAutoCompleteList(command
,
826 includeMagic
=self
.autoCompleteIncludeMagic
,
827 includeSingle
=self
.autoCompleteIncludeSingle
,
828 includeDouble
=self
.autoCompleteIncludeDouble
)
830 options
= ' '.join(list)
832 self
.AutoCompShow(offset
, options
)
834 def autoCallTipShow(self
, command
):
835 """Display argument spec and docstring in a popup window."""
836 if self
.CallTipActive():
838 (name
, argspec
, tip
) = self
.interp
.getCallTip(command
)
840 dispatcher
.send(signal
='Shell.calltip', sender
=self
, calltip
=tip
)
841 if not self
.autoCallTip
:
844 startpos
= self
.GetCurrentPos()
845 self
.write(argspec
+ ')')
846 endpos
= self
.GetCurrentPos()
847 self
.SetSelection(endpos
, startpos
)
849 curpos
= self
.GetCurrentPos()
850 tippos
= curpos
- (len(name
) + 1)
851 fallback
= curpos
- self
.GetColumn(curpos
)
852 # In case there isn't enough room, only go back to the
854 tippos
= max(tippos
, fallback
)
855 self
.CallTipShow(tippos
, tip
)
857 def writeOut(self
, text
):
858 """Replacement for stdout."""
861 def writeErr(self
, text
):
862 """Replacement for stderr."""
865 def redirectStdin(self
, redirect
=True):
866 """If redirect is true then sys.stdin will come from the shell."""
868 sys
.stdin
= self
.reader
870 sys
.stdin
= self
.stdin
872 def redirectStdout(self
, redirect
=True):
873 """If redirect is true then sys.stdout will go to the shell."""
875 sys
.stdout
= PseudoFileOut(self
.writeOut
)
877 sys
.stdout
= self
.stdout
879 def redirectStderr(self
, redirect
=True):
880 """If redirect is true then sys.stderr will go to the shell."""
882 sys
.stderr
= PseudoFileErr(self
.writeErr
)
884 sys
.stderr
= self
.stderr
887 """Return true if text is selected and can be cut."""
888 if self
.GetSelectionStart() != self
.GetSelectionEnd() \
889 and self
.GetSelectionStart() >= self
.promptPosEnd \
890 and self
.GetSelectionEnd() >= self
.promptPosEnd
:
896 """Return true if a paste should succeed."""
897 if self
.CanEdit() and editwindow
.EditWindow
.CanPaste(self
):
903 """Return true if editing should succeed."""
904 if self
.GetSelectionStart() != self
.GetSelectionEnd():
905 if self
.GetSelectionStart() >= self
.promptPosEnd \
906 and self
.GetSelectionEnd() >= self
.promptPosEnd
:
911 return self
.GetCurrentPos() >= self
.promptPosEnd
914 """Remove selection and place it on the clipboard."""
915 if self
.CanCut() and self
.CanCopy():
916 if self
.AutoCompActive():
917 self
.AutoCompCancel()
918 if self
.CallTipActive():
921 self
.ReplaceSelection('')
924 """Copy selection and place it on the clipboard."""
928 command
= self
.GetSelectedText()
929 command
= command
.replace(os
.linesep
+ ps2
, os
.linesep
)
930 command
= command
.replace(os
.linesep
+ ps1
, os
.linesep
)
931 command
= self
.lstripPrompt(text
=command
)
932 data
= wx
.TextDataObject(command
)
935 def CopyWithPrompts(self
):
936 """Copy selection, including prompts, and place it on the clipboard."""
938 command
= self
.GetSelectedText()
939 data
= wx
.TextDataObject(command
)
942 def CopyWithPromptsPrefixed(self
):
943 """Copy selection, including prompts prefixed with four
944 spaces, and place it on the clipboard."""
946 command
= self
.GetSelectedText()
948 command
= spaces
+ command
.replace(os
.linesep
,
950 data
= wx
.TextDataObject(command
)
953 def _clip(self
, data
):
954 if wx
.TheClipboard
.Open():
955 wx
.TheClipboard
.UsePrimarySelection(False)
956 wx
.TheClipboard
.SetData(data
)
957 wx
.TheClipboard
.Flush()
958 wx
.TheClipboard
.Close()
961 """Replace selection with clipboard contents."""
962 if self
.CanPaste() and wx
.TheClipboard
.Open():
964 if wx
.TheClipboard
.IsSupported(wx
.DataFormat(wx
.DF_TEXT
)):
965 data
= wx
.TextDataObject()
966 if wx
.TheClipboard
.GetData(data
):
967 self
.ReplaceSelection('')
968 command
= data
.GetText()
969 command
= command
.rstrip()
970 command
= self
.fixLineEndings(command
)
971 command
= self
.lstripPrompt(text
=command
)
972 command
= command
.replace(os
.linesep
+ ps2
, '\n')
973 command
= command
.replace(os
.linesep
, '\n')
974 command
= command
.replace('\n', os
.linesep
+ ps2
)
976 wx
.TheClipboard
.Close()
978 def PasteAndRun(self
):
979 """Replace selection with clipboard contents, run commands."""
980 if wx
.TheClipboard
.Open():
983 if wx
.TheClipboard
.IsSupported(wx
.DataFormat(wx
.DF_TEXT
)):
984 data
= wx
.TextDataObject()
985 if wx
.TheClipboard
.GetData(data
):
986 endpos
= self
.GetTextLength()
987 self
.SetCurrentPos(endpos
)
988 startpos
= self
.promptPosEnd
989 self
.SetSelection(startpos
, endpos
)
990 self
.ReplaceSelection('')
991 text
= data
.GetText()
993 text
= self
.fixLineEndings(text
)
994 text
= self
.lstripPrompt(text
)
995 text
= text
.replace(os
.linesep
+ ps1
, '\n')
996 text
= text
.replace(os
.linesep
+ ps2
, '\n')
997 text
= text
.replace(os
.linesep
, '\n')
998 lines
= text
.split('\n')
1002 if line
.strip() == ps2
.strip():
1003 # If we are pasting from something like a
1004 # web page that drops the trailing space
1005 # from the ps2 prompt of a blank line.
1007 if line
.strip() != '' and line
.lstrip() == line
:
1010 # Add the previous command to the list.
1011 commands
.append(command
)
1012 # Start a new command, which may be multiline.
1015 # Multiline command. Add to the command.
1018 commands
.append(command
)
1019 for command
in commands
:
1020 command
= command
.replace('\n', os
.linesep
+ ps2
)
1023 wx
.TheClipboard
.Close()
1025 def wrap(self
, wrap
=True):
1026 """Sets whether text is word wrapped."""
1028 self
.SetWrapMode(wrap
)
1029 except AttributeError:
1030 return 'Wrapping is not available in this version.'
1032 def zoom(self
, points
=0):
1033 """Set the zoom level.
1035 This number of points is added to the size of all fonts. It
1036 may be positive to magnify or negative to reduce."""
1037 self
.SetZoom(points
)