##// END OF EJS Templates
merge, fix crlf
merge, fix crlf

File last commit:

r1110:965ac5a8 merge
r1112:bc7ad023 merge
Show More
ipython_view.py
715 lines | 25.3 KiB | text/x-python | PythonLexer
ville
initialization (no svn history)
r988 #!/usr/bin/python
# -*- coding: iso-8859-15 -*-
'''
Gael Varoquaux
Some cosmetic changes.
r1096 Provides IPython WX console widgets.
ville
initialization (no svn history)
r988
@author: Laurent Dufrechou
laurent.dufrechou _at_ gmail.com
This WX widget is based on the original work of Eitan Isaacson
that provided the console for the GTK toolkit.
Original work from:
@author: Eitan Isaacson
@organization: IBM Corporation
@copyright: Copyright (c) 2007 IBM Corporation
@license: BSD
All rights reserved. This program and the accompanying materials are made
available under the terms of the BSD which accompanies this distribution, and
is available at U{http://www.opensource.org/licenses/bsd-license.php}
'''
__version__ = 0.8
__author__ = "Laurent Dufrechou"
__email__ = "laurent.dufrechou _at_ gmail.com"
__license__ = "BSD"
import wx
import wx.stc as stc
import wx.lib.newevent
import re
import sys
import locale
from StringIO import StringIO
try:
import IPython
except Exception,e:
raise "Error importing IPython (%s)" % str(e)
ldufrechou
Cleanup of the old stateMachine code...
r1101 from ipshell_nonblocking import NonBlockingIPShell
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091
Gael Varoquaux
Some cosmetic changes.
r1096 class WxNonBlockingIPShell(NonBlockingIPShell):
ville
initialization (no svn history)
r988 '''
Gael Varoquaux
Some cosmetic changes.
r1096 An NonBlockingIPShell Thread that is WX dependent.
ville
initialization (no svn history)
r988 '''
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 def __init__(self, parent,
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 argv=[],user_ns={},user_global_ns=None,
ville
initialization (no svn history)
r988 cin=None, cout=None, cerr=None,
Gael Varoquaux
Merged the cosmetic changes with the thread refactoring.
r1097 ask_exit_handler=None):
ville
initialization (no svn history)
r988
Gael Varoquaux
Some cosmetic changes.
r1096 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
ldufrechou
cleaning...
r1099 cin, cout, cerr,
ask_exit_handler)
ville
initialization (no svn history)
r988
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 self.parent = parent
ville
initialization (no svn history)
r988
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 self.ask_exit_callback = ask_exit_handler
ldufrechou
Cleanup of the old stateMachine code...
r1101 self._IP.exit = self._askExit
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 def addGUIShortcut(self,text,func):
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 wx.CallAfter(self.parent.add_button_handler,
button_info={ 'text':text,
'func':self.parent.doExecuteLine(func)})
ldufrechou
Merged the work with gael
r1109
Gael Varoquaux
Merged the cosmetic changes with the thread refactoring.
r1097 def _askExit(self):
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 wx.CallAfter(self.ask_exit_callback, ())
ville
initialization (no svn history)
r988
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 def _afterExecute(self):
Gael Varoquaux
Changed event into callbacks for the wxIpython
r1100 wx.CallAfter(self.parent.evtStateExecuteDone, ())
ville
initialization (no svn history)
r988
class WxConsoleView(stc.StyledTextCtrl):
'''
Specialized styled text control view for console-like workflow.
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 We use here a scintilla frontend thus it can be reused in any GUI that
supports scintilla with less work.
ville
initialization (no svn history)
r988
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
(with Black background)
ville
initialization (no svn history)
r988 @type ANSI_COLORS_BLACK: dictionary
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
(with White background)
ville
initialization (no svn history)
r988 @type ANSI_COLORS_WHITE: dictionary
@ivar color_pat: Regex of terminal color pattern
@type color_pat: _sre.SRE_Pattern
'''
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
'0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
'0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
'0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
'1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
'1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
'1;34': [12,'LIGHT BLUE'], '1;35':
[13,'MEDIUM VIOLET RED'],
'1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
'0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
'0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
'0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
'1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
'1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
'1;34': [12,'LIGHT BLUE'], '1;35':
[13,'MEDIUM VIOLET RED'],
'1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
ville
initialization (no svn history)
r988
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 def __init__(self,parent,prompt,intro="",background_color="BLACK",
pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
ville
initialization (no svn history)
r988 style=0):
'''
Initialize console view.
@param parent: Parent widget
@param prompt: User specified prompt
@type intro: string
@param intro: User specified startup introduction string
@type intro: string
@param background_color: Can be BLACK or WHITE
@type background_color: string
@param other: init param of styledTextControl (can be used as-is)
'''
stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 ####### Scintilla configuration ###################################
ville
initialization (no svn history)
r988
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
# the widget
ville
initialization (no svn history)
r988 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
#we define platform specific fonts
if wx.Platform == '__WXMSW__':
faces = { 'times': 'Times New Roman',
'mono' : 'Courier New',
'helv' : 'Arial',
'other': 'Comic Sans MS',
'size' : 10,
'size2': 8,
}
elif wx.Platform == '__WXMAC__':
faces = { 'times': 'Times New Roman',
'mono' : 'Monaco',
'helv' : 'Arial',
'other': 'Comic Sans MS',
'size' : 10,
'size2': 8,
}
else:
faces = { 'times': 'Times',
'mono' : 'Courier',
'helv' : 'Helvetica',
'other': 'new century schoolbook',
'size' : 10,
'size2': 8,
}
#We draw a line at position 80
self.SetEdgeMode(stc.STC_EDGE_LINE)
self.SetEdgeColumn(80)
self.SetEdgeColour(wx.LIGHT_GREY)
#self.SetViewWhiteSpace(True)
#self.SetViewEOL(True)
self.SetEOLMode(stc.STC_EOL_CRLF)
#self.SetWrapMode(stc.STC_WRAP_CHAR)
#self.SetWrapMode(stc.STC_WRAP_WORD)
self.SetBufferedDraw(True)
#self.SetUseAntiAliasing(True)
self.SetLayoutCache(stc.STC_CACHE_PAGE)
self.EnsureCaretVisible()
self.SetMargins(3,3) #text is moved away from border with 3px
# Suppressing Scintilla margins
self.SetMarginWidth(0,0)
self.SetMarginWidth(1,0)
self.SetMarginWidth(2,0)
# make some styles
if background_color != "BLACK":
self.background_color = "WHITE"
self.SetCaretForeground("BLACK")
self.ANSI_STYLES = self.ANSI_STYLES_WHITE
else:
self.background_color = background_color
self.SetCaretForeground("WHITE")
self.ANSI_STYLES = self.ANSI_STYLES_BLACK
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
"fore:%s,back:%s,size:%d,face:%s"
% (self.ANSI_STYLES['0;30'][1],
self.background_color,
faces['size'], faces['mono']))
ville
initialization (no svn history)
r988 self.StyleClearAll()
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
"fore:#FF0000,back:#0000FF,bold")
self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
"fore:#000000,back:#FF0000,bold")
ville
initialization (no svn history)
r988
for style in self.ANSI_STYLES.values():
self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
#######################################################################
self.indent = 0
self.prompt_count = 0
self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
self.write(intro)
self.setPrompt(prompt)
self.showPrompt()
self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
def write(self, text):
'''
Write given text to buffer.
@param text: Text to append.
@type text: string
'''
segments = self.color_pat.split(text)
segment = segments.pop(0)
self.StartStyling(self.getCurrentLineEnd(),0xFF)
self.AppendText(segment)
if segments:
ansi_tags = self.color_pat.findall(text)
for tag in ansi_tags:
i = segments.index(tag)
self.StartStyling(self.getCurrentLineEnd(),0xFF)
self.AppendText(segments[i+1])
if tag != '0':
self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
segments.pop(i)
self.moveCursor(self.getCurrentLineEnd())
def getPromptLen(self):
'''
Return the length of current prompt
'''
return len(str(self.prompt_count)) + 7
def setPrompt(self,prompt):
self.prompt = prompt
def setIndentation(self,indentation):
self.indent = indentation
def setPromptCount(self,count):
self.prompt_count = count
def showPrompt(self):
'''
Prints prompt at start of line.
@param prompt: Prompt to print.
@type prompt: string
'''
self.write(self.prompt)
#now we update the position of end of prompt
self.current_start = self.getCurrentLineEnd()
autoindent = self.indent*' '
autoindent = autoindent.replace(' ','\t')
self.write(autoindent)
def changeLine(self, text):
'''
Replace currently entered command line with given text.
@param text: Text to use as replacement.
@type text: string
'''
self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
self.ReplaceSelection(text)
self.moveCursor(self.getCurrentLineEnd())
def getCurrentPromptStart(self):
return self.current_start
def getCurrentLineStart(self):
return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
def getCurrentLineEnd(self):
return self.GetLength()
def getCurrentLine(self):
'''
Get text in current command line.
@return: Text of current command line.
@rtype: string
'''
return self.GetTextRange(self.getCurrentPromptStart(),
self.getCurrentLineEnd())
def showReturned(self, text):
'''
Show returned text from last command and print new prompt.
@param text: Text to show.
@type text: string
'''
self.write('\n'+text)
if text:
self.write('\n')
self.showPrompt()
def moveCursorOnNewValidKey(self):
#If cursor is at wrong position put it at last line...
if self.GetCurrentPos() < self.getCurrentPromptStart():
self.GotoPos(self.getCurrentPromptStart())
def removeFromTo(self,from_pos,to_pos):
if from_pos < to_pos:
self.SetSelection(from_pos,to_pos)
self.DeleteBack()
def removeCurrentLine(self):
self.LineDelete()
def moveCursor(self,position):
self.GotoPos(position)
def getCursorPos(self):
return self.GetCurrentPos()
def selectFromTo(self,from_pos,to_pos):
self.SetSelectionStart(from_pos)
self.SetSelectionEnd(to_pos)
def writeHistory(self,history):
self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
self.changeLine(history)
def writeCompletion(self, possibilities):
max_len = len(max(possibilities,key=len))
max_symbol =' '*max_len
#now we check how much symbol we can put on a line...
cursor_pos = self.getCursorPos()
test_buffer = max_symbol + ' '*4
current_lines = self.GetLineCount()
allowed_symbols = 80/len(test_buffer)
if allowed_symbols == 0:
allowed_symbols = 1
pos = 1
buf = ''
for symbol in possibilities:
#buf += symbol+'\n'#*spaces)
if pos<allowed_symbols:
spaces = max_len - len(symbol) + 4
buf += symbol+' '*spaces
pos += 1
else:
buf+=symbol+'\n'
pos = 1
self.write(buf)
def _onKeypress(self, event, skip=True):
'''
Key press callback used for correcting behavior for console-like
interfaces. For example 'home' should go to prompt, not to begining of
line.
@param widget: Widget that key press accored in.
@type widget: gtk.Widget
@param event: Event object
@type event: gtk.gdk.Event
@return: Return True if event as been catched.
@rtype: boolean
'''
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103
ville
initialization (no svn history)
r988 if event.GetKeyCode() == wx.WXK_HOME:
if event.Modifiers == wx.MOD_NONE:
self.moveCursorOnNewValidKey()
self.moveCursor(self.getCurrentPromptStart())
return True
elif event.Modifiers == wx.MOD_SHIFT:
self.moveCursorOnNewValidKey()
self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
return True
else:
return False
elif event.GetKeyCode() == wx.WXK_LEFT:
if event.Modifiers == wx.MOD_NONE:
self.moveCursorOnNewValidKey()
self.moveCursor(self.getCursorPos()-1)
if self.getCursorPos() < self.getCurrentPromptStart():
self.moveCursor(self.getCurrentPromptStart())
return True
elif event.GetKeyCode() == wx.WXK_BACK:
self.moveCursorOnNewValidKey()
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 if self.getCursorPos() > self.getCurrentPromptStart():
ville
initialization (no svn history)
r988 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 return True
ville
initialization (no svn history)
r988
if skip:
if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
self.moveCursorOnNewValidKey()
event.Skip()
return True
return False
def OnUpdateUI(self, evt):
# check for matching braces
braceAtCaret = -1
braceOpposite = -1
charBefore = None
caretPos = self.GetCurrentPos()
if caretPos > 0:
charBefore = self.GetCharAt(caretPos - 1)
styleBefore = self.GetStyleAt(caretPos - 1)
# check before
if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
braceAtCaret = caretPos - 1
# check after
if braceAtCaret < 0:
charAfter = self.GetCharAt(caretPos)
styleAfter = self.GetStyleAt(caretPos)
if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
braceAtCaret = caretPos
if braceAtCaret >= 0:
braceOpposite = self.BraceMatch(braceAtCaret)
if braceAtCaret != -1 and braceOpposite == -1:
self.BraceBadLight(braceAtCaret)
else:
self.BraceHighlight(braceAtCaret, braceOpposite)
#pt = self.PointFromPosition(braceOpposite)
#self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
#print pt
#self.Refresh(False)
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 class IPShellWidget(wx.Panel):
ville
initialization (no svn history)
r988 '''
This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107 If you want to port this to any other GUI toolkit, just replace the
WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
from whatever container you want. I've choosed to derivate from a wx.Panel
because it seems to be more useful
Any idea to make it more 'generic' welcomed.
ville
initialization (no svn history)
r988 '''
Gael Varoquaux
Merged the cosmetic changes with the thread refactoring.
r1097
def __init__(self, parent, ask_exit_handler=None, intro=None,
Gael Varoquaux
Some cosmetic changes.
r1096 background_color="BLACK", add_button_handler=None,
wx_ip_shell=None,
):
ville
initialization (no svn history)
r988 '''
Initialize.
Instanciate an IPython thread.
Instanciate a WxConsoleView.
Redirect I/O to console.
'''
wx.Panel.__init__(self,parent,-1)
ldufrechou
cleaning...
r1099 ### IPython non blocking shell instanciation ###
ville
initialization (no svn history)
r988 self.cout = StringIO()
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091
self.add_button_handler = add_button_handler
ldufrechou
revised threading model....
r1095 self.ask_exit_handler = ask_exit_handler
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091
Gael Varoquaux
Some cosmetic changes.
r1096 if wx_ip_shell is not None:
self.IP = wx_ip_shell
else:
self.IP = WxNonBlockingIPShell(self,
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 cout=self.cout,cerr=self.cout,
Gael Varoquaux
Merged the cosmetic changes with the thread refactoring.
r1097 ask_exit_handler = ask_exit_handler)
ldufrechou
cleaning...
r1099
ville
initialization (no svn history)
r988 ### IPython wx console view instanciation ###
#If user didn't defined an intro text, we create one for him
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 #If you really wnat an empty intrp just call wxIPythonViewPanel
#with intro=''
ville
initialization (no svn history)
r988 if intro == None:
welcome_text = "Welcome to WxIPython Shell.\n\n"
welcome_text+= self.IP.getBanner()
welcome_text+= "!command -> Execute command in shell\n"
welcome_text+= "TAB -> Autocompletion\n"
self.text_ctrl = WxConsoleView(self,
self.IP.getPrompt(),
intro=welcome_text,
background_color=background_color)
self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
### making the layout of the panel ###
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.text_ctrl, 1, wx.EXPAND)
self.SetAutoLayout(True)
sizer.Fit(self)
sizer.SetSizeHints(self)
self.SetSizer(sizer)
#and we focus on the widget :)
self.SetFocus()
ldufrechou
cleaning...
r1099 #widget state management (for key handling different cases)
self.setCurrentState('IDLE')
Gael Varoquaux
Some cosmetic changes.
r1096 self.pager_state = 'DONE'
ville
initialization (no svn history)
r988
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 #---------------------- IPython Thread Management ------------------------
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 def stateDoExecuteLine(self):
ldufrechou
Added help() support...
r1094 #print >>sys.__stdout__,"command:",self.getCurrentLine()
ldufrechou
Cleanup of the old stateMachine code...
r1101 line=self.text_ctrl.getCurrentLine()
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 self.IP.doExecute(line.replace('\t',' '*4))
self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
ldufrechou
cleaning...
r1099 self.setCurrentState('WAIT_END_OF_EXECUTION')
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091
def evtStateExecuteDone(self,evt):
self.doc = self.IP.getDocText()
ldufrechou
Added help() support...
r1094 self.help = self.IP.getHelpText()
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 if self.doc:
ldufrechou
cleaning...
r1099 self.pager_lines = self.doc[7:].split('\n')
self.pager_state = 'INIT'
self.setCurrentState('SHOW_DOC')
ville
initialization (no svn history)
r988 self.pager(self.doc)
ldufrechou
Doc bug correction
r1102 elif self.help:
ldufrechou
cleaning...
r1099 self.pager_lines = self.help.split('\n')
self.pager_state = 'INIT'
self.setCurrentState('SHOW_DOC')
ldufrechou
Doc bug correction
r1102 self.pager(self.help)
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 else:
self.stateShowPrompt()
def stateShowPrompt(self):
ldufrechou
cleaning...
r1099 self.setCurrentState('SHOW_PROMPT')
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 self.text_ctrl.setPrompt(self.IP.getPrompt())
self.text_ctrl.setIndentation(self.IP.getIndentation())
self.text_ctrl.setPromptCount(self.IP.getPromptCount())
rv = self.cout.getvalue()
if rv: rv = rv.strip('\n')
self.text_ctrl.showReturned(rv)
self.cout.truncate(0)
Gael Varoquaux
Some cosmetic changes.
r1096 self.IP.initHistoryIndex()
ldufrechou
cleaning...
r1099 self.setCurrentState('IDLE')
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106
ldufrechou
cleaning...
r1099 def setCurrentState(self, state):
self.cur_state = state
self.updateStatusTracker(self.cur_state)
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103
ville
initialization (no svn history)
r988 #---------------------------- IPython pager ---------------------------------------
def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103
ldufrechou
pager cleanup
r1104 if self.pager_state == 'INIT':
ldufrechou
Added help() support...
r1094 #print >>sys.__stdout__,"PAGER state:",self.pager_state
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 self.pager_nb_lines = len(self.pager_lines)
ville
initialization (no svn history)
r988 self.pager_index = 0
self.pager_do_remove = False
self.text_ctrl.write('\n')
self.pager_state = 'PROCESS_LINES'
ldufrechou
Added help() support...
r1094
ville
initialization (no svn history)
r988 if self.pager_state == 'PROCESS_LINES':
ldufrechou
Added help() support...
r1094 #print >>sys.__stdout__,"PAGER state:",self.pager_state
ville
initialization (no svn history)
r988 if self.pager_do_remove == True:
self.text_ctrl.removeCurrentLine()
self.pager_do_remove = False
if self.pager_nb_lines > 10:
ldufrechou
Added help() support...
r1094 #print >>sys.__stdout__,"PAGER processing 10 lines"
ville
initialization (no svn history)
r988 if self.pager_index > 0:
self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
else:
self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
self.pager_index += 10
self.pager_nb_lines -= 10
self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
self.pager_do_remove = True
self.pager_state = 'WAITING'
return
else:
ldufrechou
Added help() support...
r1094 #print >>sys.__stdout__,"PAGER processing last lines"
ville
initialization (no svn history)
r988 if self.pager_nb_lines > 0:
if self.pager_index > 0:
self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
else:
self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
self.pager_index += 1
self.pager_nb_lines -= 1
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 if self.pager_nb_lines > 0:
for line in self.pager_lines[self.pager_index:]:
self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
self.pager_nb_lines = 0
self.pager_state = 'DONE'
self.stateShowPrompt()
ville
initialization (no svn history)
r988
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 #------------------------ Key Handler ------------------------------------
ville
initialization (no svn history)
r988 def keyPress(self, event):
'''
Key press callback with plenty of shell goodness, like history,
autocompletions, etc.
'''
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103
ville
initialization (no svn history)
r988 if event.GetKeyCode() == ord('C'):
if event.Modifiers == wx.MOD_CONTROL:
if self.cur_state == 'WAIT_END_OF_EXECUTION':
#we raise an exception inside the IPython thread container
ldufrechou
revised threading model....
r1095 self.IP.ce.raise_exc(KeyboardInterrupt)
ville
initialization (no svn history)
r988 return
if event.KeyCode == wx.WXK_RETURN:
if self.cur_state == 'IDLE':
#we change the state ot the state machine
ldufrechou
cleaning...
r1099 self.setCurrentState('DO_EXECUTE_LINE')
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 self.stateDoExecuteLine()
ville
initialization (no svn history)
r988 return
if self.pager_state == 'WAITING':
self.pager_state = 'PROCESS_LINES'
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 self.pager(self.doc)
ville
initialization (no svn history)
r988 return
if event.GetKeyCode() in [ord('q'),ord('Q')]:
if self.pager_state == 'WAITING':
self.pager_state = 'DONE'
ldufrechou
Cleaned up version with initial WX callback (callafter) support
r1091 self.stateShowPrompt()
ville
initialization (no svn history)
r988 return
#scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 if self.cur_state == 'IDLE':
ville
initialization (no svn history)
r988 if event.KeyCode == wx.WXK_UP:
history = self.IP.historyBack()
self.text_ctrl.writeHistory(history)
return
if event.KeyCode == wx.WXK_DOWN:
history = self.IP.historyForward()
self.text_ctrl.writeHistory(history)
return
if event.KeyCode == wx.WXK_TAB:
#if line empty we disable tab completion
if not self.text_ctrl.getCurrentLine().strip():
self.text_ctrl.write('\t')
return
completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
if len(possibilities) > 1:
cur_slice = self.text_ctrl.getCurrentLine()
self.text_ctrl.write('\n')
self.text_ctrl.writeCompletion(possibilities)
self.text_ctrl.write('\n')
self.text_ctrl.showPrompt()
self.text_ctrl.write(cur_slice)
self.text_ctrl.changeLine(completed or cur_slice)
return
event.Skip()
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106 #------------------------ Hook Section -----------------------------------
ville
initialization (no svn history)
r988 def updateHistoryTracker(self,command_line):
'''
Default history tracker (does nothing)
'''
pass
def setHistoryTrackerHook(self,func):
'''
Define a new history tracker
'''
self.updateHistoryTracker = func
Gael Varoquaux
Cleaning up lignes longer than 80 characters.
r1106
ville
initialization (no svn history)
r988 def updateStatusTracker(self,status):
'''
Default status tracker (does nothing)
'''
pass
def setStatusTrackerHook(self,func):
'''
Define a new status tracker
'''
self.updateStatusTracker = func
Gael Varoquaux
Add a very simple test case to test only the widget for the wxIpython...
r1107
if __name__ == '__main__':
# Some simple code to test the shell widget.
class MainWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(300,250))
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.shell = IPShellWidget(self)
self._sizer.Add(self.shell, 1, wx.EXPAND)
self.SetSizer(self._sizer)
self.SetAutoLayout(1)
self.Show(True)
app = wx.PySimpleApp()
frame = MainWindow(None, wx.ID_ANY, 'Ipython')
frame.SetSize((780, 460))
shell = frame.shell
app.MainLoop()