# Programmer: Daniel Pozmanter
# E-mail: drpython@bluebottle.com
# Note: You must reply to the verification e-mail to get through.
#
# Copyright 2003-2007 Daniel Pozmanter
#
# Distributed under the terms of the GPL (GNU Public License)
#
# DrPython is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#Some Folding Code From demo.py by Robin Dunn
#Some more from pype by Josiah Carlson
#The Document
import os.path, re
import wx
import wx.stc
from drProperty import *
import drKeywords
import drSTC
import drEncoding
#*******************************************************************************************************
class DrText(drSTC.DrStyledTextControl):
def __init__(self, parent, id, grandparent, DynamicScript = 0, SplitView=0):
drSTC.DrStyledTextControl.__init__(self, parent, id, grandparent)
self.notebookparent = grandparent.documentnotebook
self.indentationtype = 1
if not self.grandparent.prefs.docusetabs[0]:
self.indentationtype = -1
self.filename = ""
self.mtime = -1
self.untitlednumber = 0
self.lineendingsaremixed = 0
self.IsActive = True
self.filetype = 0
self.encoding = '<Default Encoding>'
self.SetupTabs()
self.usestyles = (self.grandparent.prefs.docusestyles == 1)
self.indentationstring = ""
#Keyword Search/Context Sensitive Autoindent.
self.rekeyword = re.compile(r"(\sreturn\b)|(\sbreak\b)|(\spass\b)|(\scontinue\b)|(\sraise\b)", re.MULTILINE)
self.reslash = re.compile(r"\\\Z")
self.renonwhitespace = re.compile('\S', re.M)
self.DisableShortcuts = (SplitView == 1)
if SplitView == -1:
SplitView = 1
self.IsSplitView = SplitView
#Check this against Self.GetModify(), to ensure events are called too many times.
self.modified = False
self.DynamicScript = DynamicScript
if not DynamicScript:
self.targetPosition = 0
self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModified, id=id)
self.Bind(wx.EVT_KEY_UP, self.OnPositionChanged)
self.Bind(wx.EVT_LEFT_UP, self.OnPositionChanged)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=id)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick, id=id)
def _autoindent(self):
pos = self.GetCurrentPos()
#Strip trailing whitespace first.
currentline = self.LineFromPosition(pos)
lineendpos = self.GetLineEndPosition(currentline)
if lineendpos > pos:
self.SetTargetStart(pos)
self.SetTargetEnd(lineendpos)
t = self.GetTextRange(pos, lineendpos)
self.ReplaceTarget(t.rstrip())
#Look at last line
pos = pos - 1
clinenumber = self.LineFromPosition(pos)
linenumber = clinenumber
self.GotoPos(pos)
self.GotoLine(clinenumber)
numtabs = self.GetLineIndentation(clinenumber+1) / self.tabwidth
if self.renonwhitespace.search(self.GetLine(clinenumber+1)) is not None:
if self.renonwhitespace.search(self.GetLine(clinenumber)) is None:
numtabs += self.GetLineIndentation(clinenumber) / self.tabwidth
if numtabs == 0:
numtabs = self.GetLineIndentation(linenumber) / self.tabwidth
if (self.grandparent.prefs.docautoindent == 2) and (self.filetype == 0):
checkat = self.GetLineEndPosition(linenumber) - 1
if self.GetCharAt(checkat) == ord(':'):
numtabs = numtabs + 1
else:
lastline = self.GetLine(linenumber)
#Remove Comment:
comment = lastline.find('#')
if comment > -1:
lastline = lastline[:comment]
if self.reslash.search(lastline.rstrip()) is None:
if self.rekeyword.search(lastline) is not None:
numtabs = numtabs - 1
#Go to current line to add tabs
self.SetTargetStart(pos+1)
end = self.GetLineEndPosition(clinenumber+1)
self.SetTargetEnd(end)
self.ReplaceTarget(self.GetTextRange(pos+1, end).lstrip())
pos = pos + 1
self.GotoPos(pos)
x = 0
while x < numtabs:
self.AddText(self.addchar)
x = x + 1
#/Auto Indent Code
#Ensure proper keyboard navigation:
self.CmdKeyExecute(wx.stc.STC_CMD_CHARLEFT)
self.CmdKeyExecute(wx.stc.STC_CMD_CHARRIGHT)
def CheckIndentationFor(self, type):
text = self.GetText()
if not text:
return False
if type == -1:
return (self.respaces.search(text) is not None)
else:
return (self.retab.search(text) is not None)
def EnsureVisible(self, linenumber):
if self.grandparent.prefs.docfolding[self.filetype]:
wx.stc.StyledTextCtrl.EnsureVisible(self, linenumber)
def GetEncoding(self):
return self.encoding
def GetIndentationString(self):
return self.addchar
def GetIndentationEventText(self):
cline, cpos = self.GetCurLine()
nextline = self.GetLine(self.LineFromPosition(cpos)+1)
return cline + nextline
def GetFilename(self):
if self.filename:
return self.filename
return "Untitled " + str(self.untitlednumber)
def GetFilenameTitle(self):
if self.filename:
return os.path.split(self.filename)[1]
return "Untitled " + str(self.untitlednumber)
def OnModified(self, event):
if self.grandparent.disableeventhandling:
return
if self.DynamicScript:
return
if not self.IsSplitView:
if self.grandparent.prefs.sourcebrowserautorefresh:
if self.grandparent.SourceBrowser is not None:
self.grandparent.SourceBrowser.Browse()
modify = self.GetModify()
if (modify != self.modified) or (event is None):
self.modified = modify
if self.modified:
if self.IsActive:
pimageidx = 3
else:
pimageidx = 1
else:
if self.IsActive:
pimageidx = 2
else:
pimageidx = 0
self.SetSavePoint()
self.notebookparent.SetPageImage(self.targetPosition, pimageidx)
if not self.filename:
title = "DrPython - Untitled " + str(self.untitlednumber)
pagetext = "Untitled " + str(self.untitlednumber)
else:
title = "DrPython - " + self.filename
pagetext = os.path.basename(self.filename)
if self.modified:
title += '[Modified]'
#wx.CallAfter(self.grandparent.SetTitle, title) #workaround one for gtk, 15.03.2008, else segmentation fault
self.grandparent.SetTitle(title)
self.notebookparent.SetPageText(self.targetPosition, pagetext)
if self.grandparent.prefs.docupdateindentation:
#If deleting text, or undo/redo:
if event is not None:
modtype = event.GetModificationType()
if (modtype & wx.stc.STC_MOD_DELETETEXT) or (modtype & wx.stc.STC_PERFORMED_UNDO) or \
(modtype & wx.stc.STC_PERFORMED_REDO):
if (self.indentationtype == 0) or (self.indentationtype == 2):
result = self.CheckIndentation(self.GetText())
else:
hasit = self.CheckIndentationFor(self.indentationtype)
result = self.CheckIndentation(self.GetIndentationEventText())
if (result != self.indentationtype) and (result != 2):
result = 0
elif hasit:
result = self.indentationtype
else:
result = 2
self.indentationtype = result
self.setIndentationString()
return
else:
result = self.CheckIndentation(self.GetIndentationEventText())
else:
result = self.CheckIndentation(self.GetText())
if (result != self.indentationtype) and (result != 2):
if (self.indentationtype == 0) or (result == 0) or \
((self.indentationtype + result) == 0):
self.indentationstring = "->MIXED"
result = 0
else:
if result == -1:
self.indentationstring = "->SPACES"
elif result == 1:
self.indentationstring = "->TABS"
self.indentationtype = result
else:
self.setIndentationString()
else:
self.indentationstring = ""
if event is None:
try:
self.OnPositionChanged(None)
except:
pass
def OnPositionChanged(self, event):
if self.lineendingsaremixed:
eolmodestr = "MIXED: "
else:
eolmodestr = ''
emode = self.GetEOLMode()
if emode == wx.stc.STC_EOL_CR:
eolmodestr += "MAC"
elif emode == wx.stc.STC_EOL_CRLF:
eolmodestr += "WIN"
else:
eolmodestr += "UNIX"
if self.GetOvertype():
ovrstring = "OVR"
else:
ovrstring = "INS"
statustext = "Line: %(line)s, Col: %(col)s %(mode)s %(ovrstring)s %(ind)s" \
% {"line": self.GetCurrentLine()+1, "col": self.GetColumn(self.GetCurrentPos()), \
"mode": eolmodestr, "ovrstring": ovrstring, "ind": self.indentationstring}
#reason gtk ; workaround tow for gtk, 15.03.2008, else segmentation fault
#wx.CallAfter (self.grandparent.SetStatusText,statustext, 1)
self.grandparent.SetStatusText(statustext, 1)
if event is not None:
event.Skip()
def OnUpdateUI(self, event):
if (self.usestyles) and (self.grandparent.prefs.docparenthesismatching):
#Code for parenthesis matching from wxPython Demo.
# 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 == wx.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 == wx.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)
event.Skip()
def OnKeyDown(self, event):
result = self.grandparent.RunShortcuts(event, self, self.DisableShortcuts)
if result > -1:
if (result == wx.stc.STC_CMD_NEWLINE) and (self.grandparent.prefs.docautoindent):
self._autoindent()
if result == wx.stc.STC_CMD_TAB:
#Check Indentation for trailing spaces
pos = self.GetCurrentPos()
linenumber = self.LineFromPosition(pos)
lpos = pos - self.PositionFromLine(linenumber) - 1
#Only at the end of a line.
end = self.GetLineEndPosition(linenumber)
if pos != end:
return
ltext = self.GetLine(linenumber).rstrip(self.GetEndOfLineCharacter())
#only proceed if the text up to this point is whitespace.
if self.renonwhitespace.search(ltext[:lpos]) is not None:
return
#Get the position of where the full indentation ends:
lnws = len(ltext.rstrip())
fiendsat = lnws + (ltext[lnws:].count(self.addchar) * len(self.addchar))
#Get the diff betwixt this and the current pos:
difftwixt = len(ltext) - fiendsat
if difftwixt > 0:
#Check to make sure you are just looking at spaces:
target = ltext[fiendsat:]
for a in target:
if a != ' ':
return
#Remove the extra spaces
self.SetTargetStart(pos - difftwixt)
self.SetTargetEnd(pos)
self.ReplaceTarget('')
#/Check Indentation for trailing spaces
elif result == wx.stc.STC_CMD_DELETEBACK:
#if self.indentationtype == -1:
if self.indentationtype == -1 and self.grandparent.prefs.docuseintellibackspace[self.filetype]:
pos = self.GetCurrentPos() - 1
if chr(self.GetCharAt(pos)) == ' ':
x = 0
l = self.grandparent.prefs.doctabwidth[self.filetype]
while x < l:
c = chr(self.GetCharAt(pos))
if c == ' ':
self.CmdKeyExecute(wx.stc.STC_CMD_DELETEBACK)
else:
x = l
x += 1
pos = pos - 1
else:
event.Skip()
else:
event.Skip()
def OnMarginClick(self, event):
# fold and unfold as needed
if event.GetMargin() == 2:
lineClicked = self.LineFromPosition(event.GetPosition())
if self.GetFoldLevel(lineClicked) & wx.stc.STC_FOLDLEVELHEADERFLAG:
self.ToggleFold(lineClicked)
def SetEncoding(self, encoding):
self.encoding = encoding
def setIndentationString(self):
if self.indentationtype == 2:
self.indentationstring = "->NONE"
elif self.indentationtype == 1:
self.indentationstring = "->TABS"
elif self.indentationtype == 0:
self.indentationstring = "->MIXED"
elif self.indentationtype == -1:
self.indentationstring = "->SPACES"
def SetupLineNumbersMargin(self):
if self.grandparent.prefs.docshowlinenumbers:
linecount = self.GetLineCount()
if linecount < 1000:
linecount = 1000
lstring = str(linecount * 100)
textwidth = self.TextWidth(wx.stc.STC_STYLE_LINENUMBER, drEncoding.EncodeText(self.grandparent, lstring, self.encoding))
self.SetMarginWidth(1, textwidth)
else:
self.SetMarginWidth(1, 0)
def SetupPrefsDocument(self, notmdiupdate = 1):
if self.grandparent.prefs.doconlyusedefaultsyntaxhighlighting:
self.filetype = self.grandparent.prefs.docdefaultsyntaxhighlighting
self.SetEndAtLastLine(not self.grandparent.prefs.docscrollextrapage)
self.SetIndentationGuides(self.grandparent.prefs.docuseindentationguides)
if (len(self.filename) == 0) and not self.GetModify():
self.SetupTabs(self.indentationtype == 1)
if self.grandparent.prefs.docfolding[self.filetype]:
self.grandparent.viewmenu.Enable(self.grandparent.ID_FOLDING, True)
self.SetMarginWidth(2, 12)
self.SetMarginSensitive(2, True)
self.SetProperty("fold", "1")
else:
self.grandparent.viewmenu.Enable(self.grandparent.ID_FOLDING, False)
self.SetMarginWidth(2, 0)
self.SetMarginSensitive(2, False)
self.SetProperty("fold", "0")
#LongLineCol from Chris McDonough
#Adding if statement, else section myself, also added code to use line and/or background method:
#I put the set edge color section in under styles.
if self.grandparent.prefs.doclonglinecol > 0:
self.SetEdgeColumn(self.grandparent.prefs.doclonglinecol)
self.SetEdgeMode(wx.stc.STC_EDGE_LINE)
elif self.grandparent.prefs.doclonglinecol < 0:
self.SetEdgeColumn(abs(self.grandparent.prefs.doclonglinecol))
self.SetEdgeMode(wx.stc.STC_EDGE_BACKGROUND)
else:
self.SetEdgeMode(wx.stc.STC_EDGE_NONE)
#/LongLineCol from Chris McDonough
self.SetupLineNumbersMargin()
if notmdiupdate:
self.SetViewWhiteSpace(self.grandparent.prefs.docwhitespaceisvisible)
self.SetViewEOL(self.grandparent.prefs.docwhitespaceisvisible and self.grandparent.prefs.vieweol)
self.SetTabWidth(self.grandparent.prefs.doctabwidth[self.filetype])
if self.grandparent.prefs.docwordwrap[self.filetype]:
self.SetWrapMode(wx.stc.STC_WRAP_WORD)
else:
self.SetWrapMode(wx.stc.STC_WRAP_NONE)
self.SetKeyWords(0, drKeywords.GetKeyWords(self.filetype))
self.SetLexer(drKeywords.GetLexer(self.filetype))
indentguide = wx.LIGHT_GREY
if (self.filetype == 0) or (self.filetype == 3):
self.grandparent.prefs.txtDocumentStyleDictionary = self.grandparent.prefs.PythonStyleDictionary
cursorstyle = self.grandparent.prefs.txtDocumentStyleDictionary[15]
foldingstyle = self.grandparent.prefs.txtDocumentStyleDictionary[17]
self.SetEdgeColour(self.grandparent.prefs.txtDocumentStyleDictionary[18])
highlightlinestyle = self.grandparent.prefs.txtDocumentStyleDictionary[19]
indentguide = self.grandparent.prefs.txtDocumentStyleDictionary[20]
elif self.filetype == 1:
self.grandparent.prefs.txtDocumentStyleDictionary = self.grandparent.prefs.CPPStyleDictionary
cursorstyle = self.grandparent.prefs.txtDocumentStyleDictionary[17]
foldingstyle = self.grandparent.prefs.txtDocumentStyleDictionary[19]
self.SetEdgeColour(self.grandparent.prefs.txtDocumentStyleDictionary[20])
highlightlinestyle = self.grandparent.prefs.txtDocumentStyleDictionary[21]
elif self.filetype == 2:
self.grandparent.prefs.txtDocumentStyleDictionary = self.grandparent.prefs.HTMLStyleDictionary
cursorstyle = self.grandparent.prefs.txtDocumentStyleDictionary[18]
foldingstyle = self.grandparent.prefs.txtDocumentStyleDictionary[20]
self.SetEdgeColour(self.grandparent.prefs.txtDocumentStyleDictionary[21])
highlightlinestyle = self.grandparent.prefs.txtDocumentStyleDictionary[22]
#Folding:
foldback = getStyleProperty("back", foldingstyle)
foldfore = getStyleProperty("fore", foldingstyle)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL,wx.stc.STC_MARK_LCORNER, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_VLINE, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER,wx.stc.STC_MARK_BOXPLUS, foldback, foldfore)
self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN,wx.stc.STC_MARK_BOXMINUS, foldback, foldfore)
#Margin:
self.marginbackground = foldback
self.marginforeground = foldfore
if self.grandparent.prefs.docusestyles:
self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.grandparent.prefs.txtDocumentStyleDictionary[0])
self.StyleClearAll()
self.StartStyling(0, 0xff)
self.SetCaretForeground(cursorstyle)
if self.grandparent.prefs.dochighlightcurrentline:
self.SetCaretLineBack(highlightlinestyle)
self.SetCaretLineVisible(True)
else:
self.SetCaretLineVisible(False)
self.SetCaretWidth(self.grandparent.prefs.doccaretwidth)
self.StyleSetForeground(wx.stc.STC_STYLE_INDENTGUIDE, indentguide)
if (self.grandparent.prefs.docusestyles < 2) or (not self.filetype == 4):
self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER, self.grandparent.prefs.txtDocumentStyleDictionary[1])
self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT, self.grandparent.prefs.txtDocumentStyleDictionary[2])
self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD, self.grandparent.prefs.txtDocumentStyleDictionary[3])
drKeywords.SetSTCStyles(self.grandparent, self, self.filetype)
def SetTargetPosition(self, pos):
self.targetPosition = pos
def FoldAll(self, expanding):
lineCount = self.GetLineCount()
#Yup, this is different from the demo.py stuff.
#This is a really messed up hack of the pype.py and demo.py stuff to act
#the way I want it to...
#Folding is just ugly.
#Set stuff up first...
lines = []
#franz: lineNum not referenced
for line in xrange(lineCount):
lines.append(line)
lines.reverse()
if not expanding:
#Code Inspired by pype.py...Wake wx.stc.STC Up Before we fold!
self.HideLines(0, lineCount-1)
wx.Yield()
self.ShowLines(0, lineCount-1)
for line in xrange(lineCount):
if self.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG:
self.SetFoldExpanded(line, 1)
#Back to demo.py...mmmm, open source...Modified ever so slightly
if expanding:
#Modify the demo.py stuff to act like pype.py:
for line in lines:
a = self.GetLastChild(line, -1)
self.ShowLines(line+1,a)
self.SetFoldExpanded(line, True)
else:
#Get pype.py funky(Ever so slightly modified old bean)!
for line in lines:
a = self.GetLastChild(line, -1)
self.HideLines(line+1,a)
self.SetFoldExpanded(line, False)
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
#From demo.py (pype.py 1.1.8 uses it too!)
lastChild = self.GetLastChild(line, level)
line = line + 1
while line <= lastChild:
if force:
if visLevels > 0:
self.ShowLines(line, line)
else:
self.HideLines(line, line)
else:
if doExpand:
self.ShowLines(line, line)
if level == -1:
level = self.GetFoldLevel(line)
if level & wx.stc.STC_FOLDLEVELHEADERFLAG:
if force:
if visLevels > 1:
self.SetFoldExpanded(line, True)
else:
self.SetFoldExpanded(line, False)
line = self.Expand(line, doExpand, force, visLevels-1)
else:
if doExpand and self.GetFoldExpanded(line):
line = self.Expand(line, True, force, visLevels-1)
else:
line = self.Expand(line, False, force, visLevels-1)
else:
line = line + 1
return line
|