wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
-class ShellFrame(frame.Frame):
+class ShellFrame(frame.Frame, frame.ShellFrameMixin):
"""Frame containing the shell component."""
name = 'Shell Frame'
def __init__(self, parent=None, id=-1, title='PyShell',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, locals=None,
- InterpClass=None, *args, **kwds):
+ InterpClass=None,
+ config=None, dataDir=None,
+ *args, **kwds):
"""Create ShellFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style)
+ frame.ShellFrameMixin.__init__(self, config, dataDir)
+
+ if size == wx.DefaultSize:
+ self.SetSize((750, 525))
+
intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
- intro += '\nSponsored by Orbtech - ' + \
- 'Your source for Python programming expertise.'
self.SetStatusText(intro.replace('\n', ', '))
self.shell = Shell(parent=self, id=-1, introText=intro,
locals=locals, InterpClass=InterpClass,
+ startupScript=self.startupScript,
+ execStartupScript=self.execStartupScript,
*args, **kwds)
+
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
+ self.shell.SetFocus()
+ self.LoadSettings()
+
+
def OnClose(self, event):
"""Event handler for closing."""
# This isn't working the way I want, but I'll leave it for now.
if event.CanVeto():
event.Veto(True)
else:
+ self.SaveSettings()
self.shell.destroy()
self.Destroy()
'the other half is still in the oven.\n\n' + \
'Shell Revision: %s\n' % self.shell.revision + \
'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
+ 'Platform: %s\n' % sys.platform + \
'Python Version: %s\n' % sys.version.split()[0] + \
'wxPython Version: %s\n' % wx.VERSION_STRING + \
- 'Platform: %s\n' % sys.platform
+ ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
-class ShellFacade:
- """Simplified interface to all shell-related functionality.
+ def OnHelp(self, event):
+ """Show a help dialog."""
+ frame.ShellFrameMixin.OnHelp(self, event)
- This is a semi-transparent facade, in that all attributes of other
- are accessible, even though only some are visible to the user."""
- name = 'Shell Interface'
- revision = __revision__
+ def LoadSettings(self):
+ if self.config is not None:
+ frame.ShellFrameMixin.LoadSettings(self)
+ frame.Frame.LoadSettings(self, self.config)
+ self.shell.LoadSettings(self.config)
- def __init__(self, other):
- """Create a ShellFacade instance."""
- d = self.__dict__
- d['other'] = other
- d['helpText'] = \
-"""
+ def SaveSettings(self, force=False):
+ if self.config is not None:
+ frame.ShellFrameMixin.SaveSettings(self)
+ if self.autoSaveSettings or force:
+ frame.Frame.SaveSettings(self, self.config)
+ self.shell.SaveSettings(self.config)
+
+ def DoSaveSettings(self):
+ if self.config is not None:
+ self.SaveSettings(force=True)
+ self.config.Flush()
+
+
+
+
+HELP_TEXT = """\
* Key bindings:
Home Go to the beginning of the command or line.
Shift+Home Select to the beginning of the command or line.
End Go to the end of the line.
Ctrl+C Copy selected text, removing prompts.
Ctrl+Shift+C Copy selected text, retaining prompts.
+Alt+C Copy to the clipboard, including prefixed prompts.
Ctrl+X Cut selected text.
Ctrl+V Paste from clipboard.
Ctrl+Shift+V Paste and run multiple commands from clipboard.
Ctrl+] Increase font size.
Ctrl+[ Decrease font size.
Ctrl+= Default font size.
+Ctrl-Space Show Auto Completion.
+Ctrl-Alt-Space Show Call Tip.
+Shift+Enter Complete Text from History.
+Ctrl+F Search
+F3 Search next
+Ctrl+H "hide" lines containing selection / "unhide"
+F12 on/off "free-edit" mode
"""
+class ShellFacade:
+ """Simplified interface to all shell-related functionality.
+
+ This is a semi-transparent facade, in that all attributes of other
+ are accessible, even though only some are visible to the user."""
+
+ name = 'Shell Interface'
+ revision = __revision__
+
+ def __init__(self, other):
+ """Create a ShellFacade instance."""
+ d = self.__dict__
+ d['other'] = other
+ d['helpText'] = HELP_TEXT
+ d['this'] = other.this
+
def help(self):
"""Display some useful information about how to use the shell."""
self.write(self.helpText)
'autoCompleteIncludeDouble',
'autoCompleteIncludeMagic',
'autoCompleteIncludeSingle',
+ 'callTipInsert',
'clear',
'pause',
'prompt',
return list
+
class Shell(editwindow.EditWindow):
"""Shell based on StyledTextCtrl."""
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
- introText='', locals=None, InterpClass=None, *args, **kwds):
+ introText='', locals=None, InterpClass=None,
+ startupScript=None, execStartupScript=True,
+ *args, **kwds):
"""Create Shell instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
self.wrap()
if locals is None:
import __main__
locals = __main__.__dict__
+
# Grab these so they can be restored by self.redirect* methods.
self.stdin = sys.stdin
self.stdout = sys.stdout
self.stderr = sys.stderr
+
# Import a default interpreter class if one isn't provided.
if InterpClass == None:
from interpreter import Interpreter
else:
Interpreter = InterpClass
+
# Create a replacement for stdin.
self.reader = PseudoFileIn(self.readline, self.readlines)
self.reader.input = ''
self.reader.isreading = False
+
# Set up the interpreter.
self.interp = Interpreter(locals=locals,
rawin=self.raw_input,
stdout=PseudoFileOut(self.writeOut),
stderr=PseudoFileErr(self.writeErr),
*args, **kwds)
+
# Set up the buffer.
self.buffer = Buffer()
+
# Find out for which keycodes the interpreter will autocomplete.
self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
+
# Keep track of the last non-continuation prompt positions.
self.promptPosStart = 0
self.promptPosEnd = 0
+
# Keep track of multi-line commands.
self.more = False
+
# Create the command history. Commands are added into the
# front of the list (ie. at index 0) as they are entered.
# self.historyIndex is the current position in the history; it
# command, not in the history.
self.history = []
self.historyIndex = -1
+
+ #seb add mode for "free edit"
+ self.noteMode = 0
+ self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
+ self.searchTxt = ""
+
# Assign handlers for keyboard events.
- wx.EVT_CHAR(self, self.OnChar)
- wx.EVT_KEY_DOWN(self, self.OnKeyDown)
+ self.Bind(wx.EVT_CHAR, self.OnChar)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+
# Assign handler for idle time.
self.waiting = False
- wx.EVT_IDLE(self, self.OnIdle)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
# Display the introductory banner information.
self.showIntro(introText)
+
# Assign some pseudo keywords to the interpreter's namespace.
self.setBuiltinKeywords()
+
# Add 'shell' to the interpreter's local namespace.
self.setLocalShell()
+
+ ## NOTE: See note at bottom of this file...
+ ## #seb: File drag and drop
+ ## self.SetDropTarget( FileDropTarget(self) )
+
# Do this last so the user has complete control over their
# environment. They can override anything they want.
- self.execStartupScript(self.interp.startupScript)
+ if execStartupScript:
+ if startupScript is None:
+ startupScript = os.environ.get('PYTHONSTARTUP')
+ self.execStartupScript(startupScript)
+ else:
+ self.prompt()
+
wx.CallAfter(self.ScrollToLine, 0)
+
+ def clearHistory(self):
+ self.history = []
+ self.historyIndex = -1
+ dispatcher.send(signal="Shell.clearHistory")
+
+
def destroy(self):
del self.interp
def showIntro(self, text=''):
"""Display introductory text in the shell."""
if text:
- if not text.endswith(os.linesep):
- text += os.linesep
self.write(text)
try:
- self.write(self.interp.introText)
+ if self.interp.introText:
+ if text and not text.endswith(os.linesep):
+ self.write(os.linesep)
+ self.write(self.interp.introText)
except AttributeError:
pass
def setBuiltinKeywords(self):
"""Create pseudo keywords as part of builtins.
- This sets `close`, `exit` and `quit` to a helpful string.
+ This sets "close", "exit" and "quit" to a helpful string.
"""
import __builtin__
__builtin__.close = __builtin__.exit = __builtin__.quit = \
'Click on the close button to leave the application.'
+
def quit(self):
"""Quit the application."""
-
# XXX Good enough for now but later we want to send a close event.
-
# In the close event handler we can make sure they want to
# quit. Other applications, like PythonCard, may choose to
# hide rather than quit so we should just post the event and
# let the surrounding app decide what it wants to do.
self.write('Click on the close button to leave the application.')
+
def setLocalShell(self):
"""Add 'shell' to locals as reference to ShellFacade instance."""
self.interp.locals['shell'] = ShellFacade(other=self)
+
def execStartupScript(self, startupScript):
"""Execute the user's PYTHONSTARTUP script if they have one."""
if startupScript and os.path.isfile(startupScript):
text = 'Startup script executed: ' + startupScript
self.push('print %r; execfile(%r)' % (text, startupScript))
+ self.interp.startupScript = startupScript
else:
self.push('')
+
def about(self):
"""Display information about Py."""
text = """
Py Interpreter Revision: %s
Python Version: %s
wxPython Version: %s
+wxPython PlatformInfo: %s
Platform: %s""" % \
(__author__, VERSION, self.revision, self.interp.revision,
- sys.version.split()[0], wx.VERSION_STRING, sys.platform)
+ sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
+ sys.platform)
self.write(text.strip())
+
def OnChar(self, event):
"""Keypress event handler.
Only receives an event if OnKeyDown calls event.Skip() for the
corresponding event."""
+ if self.noteMode:
+ event.Skip()
+ return
+
# Prevent modification of previously submitted
# commands/responses.
if not self.CanEdit():
return
- key = event.KeyCode()
+ key = event.GetKeyCode()
currpos = self.GetCurrentPos()
stoppos = self.promptPosEnd
# Return (Enter) needs to be ignored in this handler.
- if key == wx.WXK_RETURN:
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
pass
elif key in self.autoCompleteKeys:
# Usually the dot (period) key activates auto completion.
self.ReplaceSelection('')
command = self.GetTextRange(stoppos, currpos) + '('
self.write('(')
- self.autoCallTipShow(command)
+ self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
else:
# Allow the normal event handling to take place.
event.Skip()
+
def OnKeyDown(self, event):
"""Key down event handler."""
- key = event.KeyCode()
+ key = event.GetKeyCode()
# If the auto-complete window is up let it do its thing.
if self.AutoCompActive():
event.Skip()
return
+
# Prevent modification of previously submitted
# commands/responses.
controlDown = event.ControlDown()
currpos = self.GetCurrentPos()
endpos = self.GetTextLength()
selecting = self.GetSelectionStart() != self.GetSelectionEnd()
+
+ if controlDown and shiftDown and key in (ord('F'), ord('f')):
+ li = self.GetCurrentLine()
+ m = self.MarkerGet(li)
+ if m & 1<<0:
+ startP = self.PositionFromLine(li)
+ self.MarkerDelete(li, 0)
+ maxli = self.GetLineCount()
+ li += 1 # li stayed visible as header-line
+ li0 = li
+ while li<maxli and self.GetLineVisible(li) == 0:
+ li += 1
+ endP = self.GetLineEndPosition(li-1)
+ self.ShowLines(li0, li-1)
+ self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
+ return
+ startP,endP = self.GetSelection()
+ endP-=1
+ startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
+
+ if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
+ endL -= 1
+
+ m = self.MarkerGet(startL)
+ self.MarkerAdd(startL, 0)
+ self.HideLines(startL+1,endL)
+ self.SetCurrentPos( startP ) # to ensure caret stays visible !
+
+ if key == wx.WXK_F12: #seb
+ if self.noteMode:
+ # self.promptPosStart not used anyway - or ?
+ self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
+ self.GotoLine(self.GetLineCount())
+ self.GotoPos(self.promptPosEnd)
+ self.prompt() #make sure we have a prompt
+ self.SetCaretForeground("black")
+ self.SetCaretWidth(1) #default
+ self.SetCaretPeriod(500) #default
+ else:
+ self.SetCaretForeground("red")
+ self.SetCaretWidth(4)
+ self.SetCaretPeriod(0) #steady
+
+ self.noteMode = not self.noteMode
+ return
+ if self.noteMode:
+ event.Skip()
+ return
+
# Return (Enter) is used to submit a command to the
# interpreter.
- if not controlDown and key == wx.WXK_RETURN:
+ if (not controlDown and not shiftDown and not altDown) and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
if self.CallTipActive():
self.CallTipCancel()
self.processLine()
- # Ctrl+Return (Cntrl+Enter) is used to insert a line break.
- elif controlDown and key == wx.WXK_RETURN:
+
+ # Complete Text (from already typed words)
+ elif shiftDown and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ self.OnShowCompHistory()
+
+ # Ctrl+Return (Ctrl+Enter) is used to insert a line break.
+ elif controlDown and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
if self.CallTipActive():
self.CallTipCancel()
if currpos == endpos:
self.processLine()
else:
self.insertLineBreak()
+
# Let Ctrl-Alt-* get handled normally.
elif controlDown and altDown:
event.Skip()
+
# Clear the current, unexecuted command.
elif key == wx.WXK_ESCAPE:
if self.CallTipActive():
event.Skip()
else:
self.clearCommand()
+
+ # Clear the current command
+ elif key == wx.WXK_BACK and controlDown and shiftDown:
+ self.clearCommand()
+
# Increase font size.
- elif controlDown and key in (ord(']'),):
+ elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
dispatcher.send(signal='FontIncrease')
+
# Decrease font size.
- elif controlDown and key in (ord('['),):
+ elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
dispatcher.send(signal='FontDecrease')
+
# Default font size.
- elif controlDown and key in (ord('='),):
+ elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
dispatcher.send(signal='FontDefault')
+
# Cut to the clipboard.
elif (controlDown and key in (ord('X'), ord('x'))) \
- or (shiftDown and key == wx.WXK_DELETE):
+ or (shiftDown and key == wx.WXK_DELETE):
self.Cut()
+
# Copy to the clipboard.
elif controlDown and not shiftDown \
- and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
self.Copy()
+
# Copy to the clipboard, including prompts.
elif controlDown and shiftDown \
- and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
self.CopyWithPrompts()
+
# Copy to the clipboard, including prefixed prompts.
elif altDown and not controlDown \
- and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
self.CopyWithPromptsPrefixed()
+
# Home needs to be aware of the prompt.
elif key == wx.WXK_HOME:
home = self.promptPosEnd
self.EnsureCaretVisible()
else:
event.Skip()
+
#
# The following handlers modify text, so we need to see if
# there is a selection that includes text prior to the prompt.
# Don't modify a selection with text prior to the prompt.
elif selecting and key not in NAVKEYS and not self.CanEdit():
pass
+
# Paste from the clipboard.
elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
or (shiftDown and not controlDown and key == wx.WXK_INSERT):
self.Paste()
+
+ # manually invoke AutoComplete and Calltips
+ elif controlDown and key == wx.WXK_SPACE:
+ self.OnCallTipAutoCompleteManually(shiftDown)
+
# Paste from the clipboard, run commands.
elif controlDown and shiftDown and key in (ord('V'), ord('v')):
self.PasteAndRun()
+
# Replace with the previous command from the history buffer.
elif (controlDown and key == wx.WXK_UP) \
or (altDown and key in (ord('P'), ord('p'))):
self.OnHistoryReplace(step=+1)
+
# Replace with the next command from the history buffer.
elif (controlDown and key == wx.WXK_DOWN) \
or (altDown and key in (ord('N'), ord('n'))):
self.OnHistoryReplace(step=-1)
+
# Insert the previous command from the history buffer.
elif (shiftDown and key == wx.WXK_UP) and self.CanEdit():
self.OnHistoryInsert(step=+1)
+
# Insert the next command from the history buffer.
elif (shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
self.OnHistoryInsert(step=-1)
+
# Search up the history for the text in front of the cursor.
elif key == wx.WXK_F8:
self.OnHistorySearch()
+
# Don't backspace over the latest non-continuation prompt.
elif key == wx.WXK_BACK:
if selecting and self.CanEdit():
event.Skip()
elif currpos > self.promptPosEnd:
event.Skip()
+
# Only allow these keys after the latest prompt.
elif key in (wx.WXK_TAB, wx.WXK_DELETE):
if self.CanEdit():
event.Skip()
+
# Don't toggle between insert mode and overwrite mode.
elif key == wx.WXK_INSERT:
pass
+
# Don't allow line deletion.
elif controlDown and key in (ord('L'), ord('l')):
pass
+
# Don't allow line transposition.
elif controlDown and key in (ord('T'), ord('t')):
pass
+
# Basic navigation keys should work anywhere.
elif key in NAVKEYS:
event.Skip()
+
# Protect the readonly portion of the shell.
elif not self.CanEdit():
pass
+
else:
event.Skip()
+
+ def OnShowCompHistory(self):
+ """Show possible autocompletion Words from already typed words."""
+
+ #copy from history
+ his = self.history[:]
+
+ #put together in one string
+ joined = " ".join (his)
+ import re
+
+ #sort out only "good" words
+ newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
+
+ #length > 1 (mix out "trash")
+ thlist = []
+ for i in newlist:
+ if len (i) > 1:
+ thlist.append (i)
+
+ #unique (no duplicate words
+ #oneliner from german python forum => unique list
+ unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
+
+ #sort lowercase
+ unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
+
+ #this is more convenient, isn't it?
+ self.AutoCompSetIgnoreCase(True)
+
+ #join again together in a string
+ stringlist = " ".join(unlist)
+
+ #pos von 0 noch ausrechnen
+
+ #how big is the offset?
+ cpos = self.GetCurrentPos() - 1
+ while chr (self.GetCharAt (cpos)).isalnum():
+ cpos -= 1
+
+ #the most important part
+ self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
+
+
def clearCommand(self):
"""Delete the current, unexecuted command."""
startpos = self.promptPosEnd
self.write(os.linesep)
else:
self.push(command)
+ wx.FutureCall(1, self.EnsureCaretVisible)
# Or replace the current command with the other command.
else:
# If the line contains a command (even an invalid one).
text = text[ps2size:]
return text
- def push(self, command):
+ def push(self, command, silent = False):
"""Send command to the interpreter for execution."""
- self.write(os.linesep)
+ if not silent:
+ self.write(os.linesep)
busy = wx.BusyCursor()
self.waiting = True
self.more = self.interp.push(command)
del busy
if not self.more:
self.addHistory(command.rstrip())
- self.prompt()
+ if not silent:
+ self.prompt()
def addHistory(self, command):
"""Add command to the command history."""
if command != '' \
and (len(self.history) == 0 or command != self.history[0]):
self.history.insert(0, command)
+ dispatcher.send(signal="Shell.addHistory", command=command)
def write(self, text):
"""Display text in the shell.
finally:
file.close()
- def autoCompleteShow(self, command):
+ def autoCompleteShow(self, command, offset = 0):
"""Display auto-completion popup list."""
self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
includeDouble=self.autoCompleteIncludeDouble)
if list:
options = ' '.join(list)
- offset = 0
+ #offset = 0
self.AutoCompShow(offset, options)
- def autoCallTipShow(self, command):
+ def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
"""Display argument spec and docstring in a popup window."""
if self.CallTipActive():
self.CallTipCancel()
(name, argspec, tip) = self.interp.getCallTip(command)
if tip:
dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
- if not self.autoCallTip:
+ if not self.autoCallTip and not forceCallTip:
return
- if argspec:
+ if argspec and insertcalltip and self.callTipInsert:
startpos = self.GetCurrentPos()
self.write(argspec + ')')
endpos = self.GetCurrentPos()
# fallback.
tippos = max(tippos, fallback)
self.CallTipShow(tippos, tip)
+
+ def OnCallTipAutoCompleteManually (self, shiftDown):
+ """AutoComplete and Calltips manually."""
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ currpos = self.GetCurrentPos()
+ stoppos = self.promptPosEnd
+
+ cpos = currpos
+ #go back until '.' is found
+ pointavailpos = -1
+ while cpos >= stoppos:
+ if self.GetCharAt(cpos) == ord ('.'):
+ pointavailpos = cpos
+ break
+ cpos -= 1
+
+ #word from non whitespace until '.'
+ if pointavailpos != -1:
+ #look backward for first whitespace char
+ textbehind = self.GetTextRange (pointavailpos + 1, currpos)
+ pointavailpos += 1
+
+ if not shiftDown:
+ #call AutoComplete
+ stoppos = self.promptPosEnd
+ textbefore = self.GetTextRange(stoppos, pointavailpos)
+ self.autoCompleteShow(textbefore, len (textbehind))
+ else:
+ #call CallTips
+ cpos = pointavailpos
+ begpos = -1
+ while cpos > stoppos:
+ if chr(self.GetCharAt(cpos)).isspace():
+ begpos = cpos
+ break
+ cpos -= 1
+ if begpos == -1:
+ begpos = cpos
+ ctips = self.GetTextRange (begpos, currpos)
+ ctindex = ctips.find ('(')
+ if ctindex != -1 and not self.CallTipActive():
+ #insert calltip, if current pos is '(', otherwise show it only
+ self.autoCallTipShow(ctips[:ctindex + 1],
+ self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),
+ True)
+
def writeOut(self, text):
"""Replacement for stdout."""
self.write(command)
wx.TheClipboard.Close()
+
def PasteAndRun(self):
"""Replace selection with clipboard contents, run commands."""
+ text = ''
if wx.TheClipboard.Open():
- ps1 = str(sys.ps1)
- ps2 = str(sys.ps2)
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
data = wx.TextDataObject()
if wx.TheClipboard.GetData(data):
- endpos = self.GetTextLength()
- self.SetCurrentPos(endpos)
- startpos = self.promptPosEnd
- self.SetSelection(startpos, endpos)
- self.ReplaceSelection('')
text = data.GetText()
- text = text.lstrip()
- text = self.fixLineEndings(text)
- text = self.lstripPrompt(text)
- text = text.replace(os.linesep + ps1, '\n')
- text = text.replace(os.linesep + ps2, '\n')
- text = text.replace(os.linesep, '\n')
- lines = text.split('\n')
- commands = []
- command = ''
- for line in lines:
- if line.strip() == ps2.strip():
- # If we are pasting from something like a
- # web page that drops the trailing space
- # from the ps2 prompt of a blank line.
- line = ''
- if line.strip() != '' and line.lstrip() == line:
- # New command.
- if command:
- # Add the previous command to the list.
- commands.append(command)
- # Start a new command, which may be multiline.
- command = line
- else:
- # Multiline command. Add to the command.
- command += '\n'
- command += line
- commands.append(command)
- for command in commands:
- command = command.replace('\n', os.linesep + ps2)
- self.write(command)
- self.processLine()
wx.TheClipboard.Close()
+ if text:
+ self.Execute(text)
+
+
+ def Execute(self, text):
+ """Replace selection with text and run commands."""
+ ps1 = str(sys.ps1)
+ ps2 = str(sys.ps2)
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ startpos = self.promptPosEnd
+ self.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+ text = text.lstrip()
+ text = self.fixLineEndings(text)
+ text = self.lstripPrompt(text)
+ text = text.replace(os.linesep + ps1, '\n')
+ text = text.replace(os.linesep + ps2, '\n')
+ text = text.replace(os.linesep, '\n')
+ lines = text.split('\n')
+ commands = []
+ command = ''
+ for line in lines:
+ if line.strip() == ps2.strip():
+ # If we are pasting from something like a
+ # web page that drops the trailing space
+ # from the ps2 prompt of a blank line.
+ line = ''
+ lstrip = line.lstrip()
+ if line.strip() != '' and lstrip == line and \
+ lstrip[:4] not in ['else','elif'] and \
+ lstrip[:6] != 'except':
+ # New command.
+ if command:
+ # Add the previous command to the list.
+ commands.append(command)
+ # Start a new command, which may be multiline.
+ command = line
+ else:
+ # Multiline command. Add to the command.
+ command += '\n'
+ command += line
+ commands.append(command)
+ for command in commands:
+ command = command.replace('\n', os.linesep + ps2)
+ self.write(command)
+ self.processLine()
+
def wrap(self, wrap=True):
"""Sets whether text is word wrapped."""
This number of points is added to the size of all fonts. It
may be positive to magnify or negative to reduce."""
self.SetZoom(points)
+
+
+
+ def LoadSettings(self, config):
+ self.autoComplete = config.ReadBool('Options/AutoComplete', True)
+ self.autoCompleteIncludeMagic = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
+ self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
+ self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
+
+ self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
+ self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
+ self.SetWrapMode(config.ReadBool('View/WrapMode', True))
+
+ useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
+ self.SetUseAntiAliasing(useAA)
+ self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
+ self.setDisplayLineNumbers (self.lineNumbers)
+ zoom = config.ReadInt('View/Zoom/Shell', -99)
+ if zoom != -99:
+ self.SetZoom(zoom)
+
+
+
+ def SaveSettings(self, config):
+ config.WriteBool('Options/AutoComplete', self.autoComplete)
+ config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
+ config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
+ config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
+ config.WriteBool('Options/AutoCallTip', self.autoCallTip)
+ config.WriteBool('Options/CallTipInsert', self.callTipInsert)
+ config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
+ config.WriteBool('View/WrapMode', self.GetWrapMode())
+ config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
+ config.WriteInt('View/Zoom/Shell', self.GetZoom())
+
+
+
+## NOTE: The DnD of file names is disabled until I can figure out how
+## best to still allow DnD of text.
+
+
+## #seb : File drag and drop
+## class FileDropTarget(wx.FileDropTarget):
+## def __init__(self, obj):
+## wx.FileDropTarget.__init__(self)
+## self.obj = obj
+## def OnDropFiles(self, x, y, filenames):
+## if len(filenames) == 1:
+## txt = 'r\"%s\"' % filenames[0]
+## else:
+## txt = '( '
+## for f in filenames:
+## txt += 'r\"%s\" , ' % f
+## txt += ')'
+## self.obj.AppendText(txt)
+## pos = self.obj.GetCurrentPos()
+## self.obj.SetCurrentPos( pos )
+## self.obj.SetSelection( pos, pos )
+
+
+
+## class TextAndFileDropTarget(wx.DropTarget):
+## def __init__(self, shell):
+## wx.DropTarget.__init__(self)
+## self.shell = shell
+## self.compdo = wx.DataObjectComposite()
+## self.textdo = wx.TextDataObject()
+## self.filedo = wx.FileDataObject()
+## self.compdo.Add(self.textdo)
+## self.compdo.Add(self.filedo, True)
+
+## self.SetDataObject(self.compdo)
+
+## def OnDrop(self, x, y):
+## return True
+
+## def OnData(self, x, y, result):
+## self.GetData()
+## if self.textdo.GetTextLength() > 1:
+## text = self.textdo.GetText()
+## # *** Do somethign with the dragged text here...
+## self.textdo.SetText('')
+## else:
+## filenames = str(self.filename.GetFilenames())
+## if len(filenames) == 1:
+## txt = 'r\"%s\"' % filenames[0]
+## else:
+## txt = '( '
+## for f in filenames:
+## txt += 'r\"%s\" , ' % f
+## txt += ')'
+## self.shell.AppendText(txt)
+## pos = self.shell.GetCurrentPos()
+## self.shell.SetCurrentPos( pos )
+## self.shell.SetSelection( pos, pos )
+
+## return result
+