home *** CD-ROM | disk | FTP | other *** search
- """A utility class for a code container.
-
- A code container is a class which holds source code for a debugger. It knows how
- to color the text, and also how to translate lines into offsets, and back.
- """
-
- import string, sys
- from win32com.axdebug import axdebug
- import tokenize
- from util import RaiseNotImpl, _wrap
-
- from win32com.server.exception import Exception
- import win32api, winerror
- import contexts
-
- _keywords = {} # set of Python keywords
- for name in string.split("""
- and assert break class continue def del elif else except exec
- finally for from global if import in is lambda not
- or pass print raise return try while
- """):
- _keywords[name] = 1
-
- class SourceCodeContainer:
- def __init__(self, text, fileName = "<Remove Me!>", sourceContext = 0, startLineNumber = 0, site = None, debugDocument = None):
- self.sourceContext = sourceContext # The source context added by a smart host.
- self.text = None
- if text:
- self.text = str(text)# Convert from Unicode if necessary.
- self._buildlines()
- self.nextLineNo = 0
- self.fileName = fileName
- self.codeContexts = {}
- self.site = site
- self.startLineNumber = startLineNumber
- self.debugDocument = None
- def _Close(self):
- self.text = self.lines = self.lineOffsets = None
- self.codeContexts = None
- def GetText(self):
- return self.text
- def GetName(self, dnt):
- assert 0, "You must subclass this"
- def GetFileName(self):
- return self.fileName
-
- def GetPositionOfLine(self, cLineNumber):
- self.GetText() # Prime us.
- try:
- return self.lineOffsets[cLineNumber]
- except IndexError:
- raise Exception(scode=winerror.S_FALSE)
- def GetLineOfPosition(self, charPos):
- self.GetText() # Prime us.
- lastOffset = 0
- lineNo = 0
- for lineOffset in self.lineOffsets[1:]:
- if lineOffset > charPos:
- break
- lastOffset = lineOffset
- lineNo = lineNo + 1
- else: # for not broken.
- # print "Cant find", charPos, "in", self.lineOffsets
- raise Exception(scode=winerror.S_FALSE)
- # print "GLOP ret=",lineNo, (charPos-lastOffset)
- return lineNo, (charPos-lastOffset)
-
- def GetNextLine(self):
- if self.nextLineNo>=len(self.lines):
- self.nextLineNo = 0 # auto-reset.
- return ""
- rc = self.lines[self.nextLineNo]
- self.nextLineNo = self.nextLineNo + 1
- return rc
-
- def GetLine(self, num):
- self.GetText() # Prime us.
- return self.lines[num]
-
- def GetNumChars(self):
- return len(self.GetText())
-
- def GetNumLines(self):
- self.GetText() # Prime us.
- return len(self.lines)
-
- def _buildline(self, pos):
- i = string.find(self.text, '\n', pos)
- if i < 0:
- newpos = len(self.text)
- else:
- newpos = i+1
- r = self.text[pos:newpos]
- return r, newpos
-
- def _buildlines(self):
- self.lines = []
- self.lineOffsets = [0]
- line, pos = self._buildline(0)
- while line:
- self.lines.append(line)
- self.lineOffsets.append(pos)
- line, pos = self._buildline(pos)
-
- def _ProcessToken(self, type, token, (srow, scol), (erow, ecol), line):
- self.GetText() # Prime us.
- linenum = srow - 1 # Lines zero based for us too.
- realCharPos = self.lineOffsets[linenum] + scol
- numskipped = realCharPos - self.lastPos
- if numskipped==0:
- pass
- elif numskipped==1:
- self.attrs.append(axdebug.SOURCETEXT_ATTR_COMMENT)
- else:
- self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numskipped))
- kwSize = len(token)
- self.lastPos = realCharPos + kwSize
- attr = 0
-
- if type==tokenize.NAME:
- if _keywords.has_key(token):
- attr = axdebug.SOURCETEXT_ATTR_KEYWORD
- elif type==tokenize.STRING:
- attr = axdebug.SOURCETEXT_ATTR_STRING
- elif type==tokenize.NUMBER:
- attr = axdebug.SOURCETEXT_ATTR_NUMBER
- elif type==tokenize.OP:
- attr = axdebug.SOURCETEXT_ATTR_OPERATOR
- elif type==tokenize.COMMENT:
- attr = axdebug.SOURCETEXT_ATTR_COMMENT
- # else attr remains zero...
- if kwSize==0:
- pass
- elif kwSize==1:
- self.attrs.append(attr)
- else:
- self.attrs.append((attr, kwSize))
-
- def GetSyntaxColorAttributes(self):
- self.lastPos = 0
- self.attrs = []
- try:
- tokenize.tokenize(self.GetNextLine, self._ProcessToken)
- except tokenize.TokenError:
- pass # Ignore - will cause all subsequent text to be commented.
- numAtEnd = len(self.GetText()) - self.lastPos
- if numAtEnd:
- self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numAtEnd))
- return self.attrs
-
- # We also provide and manage DebugDocumentContext objects
- def _MakeDebugCodeContext(self, lineNo, charPos, len):
- return _wrap(contexts.DebugCodeContext(lineNo, charPos, len, self, self.site), axdebug.IID_IDebugCodeContext)
- # Make a context at the given position. It should take up the entire context.
- def _MakeContextAtPosition(self, charPos):
- lineNo, offset = self.GetLineOfPosition(charPos)
- try:
- endPos = self.GetPositionOfLine(lineNo+1)
- except:
- endPos = charPos
- codecontext = self._MakeDebugCodeContext(lineNo, charPos, endPos-charPos)
- return codecontext
-
- # Returns a DebugCodeContext. debugDocument can be None for smart hosts.
- def GetCodeContextAtPosition(self, charPos):
- # trace("GetContextOfPos", charPos, maxChars)
- # Convert to line number.
- lineNo, offset = self.GetLineOfPosition(charPos)
- charPos = self.GetPositionOfLine(lineNo)
- try:
- cc = self.codeContexts[charPos]
- # trace(" GetContextOfPos using existing")
- except KeyError:
- cc = self._MakeContextAtPosition(charPos)
- self.codeContexts[charPos] = cc
- return cc
-
- class SourceModuleContainer(SourceCodeContainer):
- def __init__(self, module):
- self.module = module
- if hasattr(module, '__file__'):
- fname = self.module.__file__
- # Check for .pyc or .pyo or even .pys!
- if fname[-1] in ['O','o','C','c', 'S', 's']: fname = fname[:-1]
- try:
- fname = win32api.GetFullPathName(fname)
- except win32api.error:
- pass
- else:
- if module.__name__=='__main__' and len(sys.argv)>0:
- fname = sys.argv[0]
- else:
- fname = "<Unknown!>"
- SourceCodeContainer.__init__(self, None, fname)
-
- def GetText(self):
- if self.text is None:
- fname = self.GetFileName()
- if fname:
- try:
- self.text = open(fname, "r").read()
- except IOError, details:
- self.text = "# Exception opening file\n# %s" % (`details`)
- else:
- self.text = "# No file available for module '%s'" % (self.module)
- self._buildlines()
- return self.text
-
- def GetName(self, dnt):
- name = self.module.__name__
- try:
- fname = win32api.GetFullPathName(self.module.__file__)
- except win32api.error:
- fname = self.module.__file__
- except AttributeError:
- fname = name
- if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
- return string.split(name, ".")[-1]
- elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
- return fname
- elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
- return os.path.split(fname)[1]
- elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
- return "file:%s" % fname
- else:
- raise Exception(scode=winerror.E_UNEXPECTED)
-
- if __name__=='__main__':
- import sys
- sys.path.append(".")
- import ttest
- sc = SourceModuleContainer(ttest)
- # sc = SourceCodeContainer(open(sys.argv[1], "rb").read(), sys.argv[1])
- attrs = sc.GetSyntaxColorAttributes()
- attrlen = 0
- for attr in attrs:
- if type(attr)==type(()):
- attrlen = attrlen + attr[1]
- else:
- attrlen = attrlen + 1
- text = sc.GetText()
- if attrlen!=len(text):
- print "Lengths dont match!!! (%d/%d)" % (attrlen, len(text))
-
- # print "Attributes:"
- # print attrs
- print "GetLineOfPos=", sc.GetLineOfPosition(0)
- print "GetLineOfPos=", sc.GetLineOfPosition(4)
- print "GetLineOfPos=", sc.GetLineOfPosition(10)