home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_win32comext_axdebug_codecontainer.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  7.5 KB  |  249 lines

  1. """A utility class for a code container.
  2.  
  3. A code container is a class which holds source code for a debugger.  It knows how
  4. to color the text, and also how to translate lines into offsets, and back.
  5. """
  6.  
  7. import string, sys
  8. from win32com.axdebug import axdebug
  9. import tokenize
  10. from util import RaiseNotImpl, _wrap
  11.  
  12. from win32com.server.exception import Exception
  13. import win32api, winerror
  14. import contexts
  15.  
  16. _keywords = {}                # set of Python keywords
  17. for name in string.split("""
  18.  and assert break class continue def del elif else except exec
  19.  finally for from global if import in is lambda not
  20.  or pass print raise return try while
  21.  """):
  22.     _keywords[name] = 1
  23.  
  24. class SourceCodeContainer:
  25.     def __init__(self, text, fileName = "<Remove Me!>", sourceContext = 0, startLineNumber = 0, site = None, debugDocument = None):
  26.         self.sourceContext = sourceContext # The source context added by a smart host.
  27.         self.text = None
  28.         if text: 
  29.             self.text = str(text)# Convert from Unicode if necessary.
  30.             self._buildlines()
  31.         self.nextLineNo = 0
  32.         self.fileName = fileName
  33.         self.codeContexts = {}
  34.         self.site = site
  35.         self.startLineNumber = startLineNumber
  36.         self.debugDocument = None
  37.     def _Close(self):
  38.         self.text = self.lines = self.lineOffsets = None
  39.         self.codeContexts = None
  40.     def GetText(self):
  41.         return self.text
  42.     def GetName(self, dnt):
  43.         assert 0, "You must subclass this"
  44.     def GetFileName(self):
  45.         return self.fileName
  46.  
  47.     def GetPositionOfLine(self, cLineNumber):
  48.         self.GetText() # Prime us.
  49.         try:
  50.             return self.lineOffsets[cLineNumber]
  51.         except IndexError:
  52.             raise Exception(scode=winerror.S_FALSE)
  53.     def GetLineOfPosition(self, charPos):
  54.         self.GetText() # Prime us.
  55.         lastOffset = 0
  56.         lineNo = 0
  57.         for lineOffset in self.lineOffsets[1:]:
  58.             if lineOffset > charPos:
  59.                 break
  60.             lastOffset = lineOffset
  61.             lineNo = lineNo + 1
  62.         else: # for not broken.
  63. #            print "Cant find", charPos, "in", self.lineOffsets
  64.             raise Exception(scode=winerror.S_FALSE)
  65. #        print "GLOP ret=",lineNo,     (charPos-lastOffset)
  66.         return lineNo,     (charPos-lastOffset)
  67.  
  68.     def GetNextLine(self):
  69.         if self.nextLineNo>=len(self.lines):
  70.             self.nextLineNo = 0 # auto-reset.
  71.             return ""
  72.         rc = self.lines[self.nextLineNo]
  73.         self.nextLineNo = self.nextLineNo + 1
  74.         return rc
  75.         
  76.     def GetLine(self, num):
  77.         self.GetText() # Prime us.
  78.         return self.lines[num]
  79.         
  80.     def GetNumChars(self):
  81.         return len(self.GetText())
  82.         
  83.     def GetNumLines(self):
  84.         self.GetText() # Prime us.
  85.         return len(self.lines)
  86.  
  87.     def _buildline(self, pos):
  88.         i = string.find(self.text, '\n', pos)
  89.         if i < 0:
  90.             newpos = len(self.text)
  91.         else:
  92.             newpos = i+1
  93.         r = self.text[pos:newpos]
  94.         return r, newpos
  95.         
  96.     def _buildlines(self):
  97.         self.lines = []
  98.         self.lineOffsets = [0]
  99.         line, pos = self._buildline(0)
  100.         while line:
  101.             self.lines.append(line)
  102.             self.lineOffsets.append(pos)
  103.             line, pos = self._buildline(pos)
  104.  
  105.     def _ProcessToken(self, type, token, (srow, scol), (erow, ecol), line):
  106.         self.GetText() # Prime us.
  107.         linenum = srow - 1 # Lines zero based for us too.
  108.         realCharPos = self.lineOffsets[linenum] + scol
  109.         numskipped = realCharPos - self.lastPos
  110.         if numskipped==0:
  111.             pass
  112.         elif numskipped==1:
  113.             self.attrs.append(axdebug.SOURCETEXT_ATTR_COMMENT)
  114.         else:
  115.             self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numskipped))
  116.         kwSize = len(token)
  117.         self.lastPos = realCharPos + kwSize
  118.         attr = 0
  119.  
  120.         if type==tokenize.NAME:
  121.             if _keywords.has_key(token):
  122.                 attr = axdebug.SOURCETEXT_ATTR_KEYWORD
  123.         elif type==tokenize.STRING:
  124.             attr = axdebug.SOURCETEXT_ATTR_STRING
  125.         elif type==tokenize.NUMBER:
  126.             attr = axdebug.SOURCETEXT_ATTR_NUMBER
  127.         elif type==tokenize.OP:
  128.             attr = axdebug.SOURCETEXT_ATTR_OPERATOR
  129.         elif type==tokenize.COMMENT:
  130.             attr = axdebug.SOURCETEXT_ATTR_COMMENT
  131.         # else attr remains zero...
  132.         if kwSize==0:
  133.             pass
  134.         elif kwSize==1:
  135.             self.attrs.append(attr)
  136.         else:
  137.             self.attrs.append((attr, kwSize))
  138.  
  139.     def GetSyntaxColorAttributes(self):
  140.         self.lastPos = 0
  141.         self.attrs = []
  142.         try:
  143.             tokenize.tokenize(self.GetNextLine, self._ProcessToken)
  144.         except tokenize.TokenError:
  145.             pass # Ignore - will cause all subsequent text to be commented.
  146.         numAtEnd = len(self.GetText()) - self.lastPos
  147.         if numAtEnd:
  148.             self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numAtEnd))
  149.         return self.attrs
  150.  
  151.     # We also provide and manage DebugDocumentContext objects
  152.     def _MakeDebugCodeContext(self, lineNo, charPos, len):
  153.         return _wrap(contexts.DebugCodeContext(lineNo, charPos, len, self, self.site), axdebug.IID_IDebugCodeContext)
  154.     # Make a context at the given position.  It should take up the entire context.
  155.     def _MakeContextAtPosition(self, charPos):
  156.         lineNo, offset = self.GetLineOfPosition(charPos)
  157.         try:
  158.             endPos = self.GetPositionOfLine(lineNo+1)
  159.         except:
  160.             endPos = charPos
  161.         codecontext = self._MakeDebugCodeContext(lineNo, charPos, endPos-charPos)
  162.         return codecontext
  163.  
  164.     # Returns a DebugCodeContext.  debugDocument can be None for smart hosts.
  165.     def GetCodeContextAtPosition(self, charPos):
  166. #        trace("GetContextOfPos", charPos, maxChars)
  167.         # Convert to line number.
  168.         lineNo, offset = self.GetLineOfPosition(charPos)
  169.         charPos = self.GetPositionOfLine(lineNo)
  170.         try:
  171.             cc = self.codeContexts[charPos]
  172. #            trace(" GetContextOfPos using existing")
  173.         except KeyError:
  174.             cc = self._MakeContextAtPosition(charPos)
  175.             self.codeContexts[charPos] = cc
  176.         return cc
  177.  
  178. class SourceModuleContainer(SourceCodeContainer):
  179.     def __init__(self, module):
  180.         self.module = module
  181.         if hasattr(module, '__file__'):
  182.             fname = self.module.__file__
  183.             # Check for .pyc or .pyo or even .pys!
  184.             if fname[-1] in ['O','o','C','c', 'S', 's']: fname = fname[:-1]
  185.             try:
  186.                 fname = win32api.GetFullPathName(fname)
  187.             except win32api.error:
  188.                 pass
  189.         else:
  190.             if module.__name__=='__main__' and len(sys.argv)>0:
  191.                 fname = sys.argv[0]
  192.             else:
  193.                 fname = "<Unknown!>"
  194.         SourceCodeContainer.__init__(self, None, fname)
  195.  
  196.     def GetText(self):
  197.         if self.text is None:
  198.             fname = self.GetFileName()
  199.             if fname:
  200.                 try:
  201.                     self.text = open(fname, "r").read()
  202.                 except IOError, details:
  203.                     self.text = "# Exception opening file\n# %s" % (`details`)
  204.             else:
  205.                 self.text = "# No file available for module '%s'" % (self.module)
  206.             self._buildlines()
  207.         return self.text
  208.  
  209.     def GetName(self, dnt):
  210.         name = self.module.__name__
  211.         try:
  212.             fname = win32api.GetFullPathName(self.module.__file__)
  213.         except win32api.error:
  214.             fname = self.module.__file__
  215.         except AttributeError:
  216.             fname = name
  217.         if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
  218.             return string.split(name, ".")[-1]
  219.         elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
  220.             return fname
  221.         elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
  222.             return os.path.split(fname)[1]
  223.         elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
  224.             return "file:%s" % fname
  225.         else:
  226.             raise Exception(scode=winerror.E_UNEXPECTED)
  227.  
  228. if __name__=='__main__':
  229.     import sys
  230.     sys.path.append(".")
  231.     import ttest
  232.     sc = SourceModuleContainer(ttest)
  233. #    sc = SourceCodeContainer(open(sys.argv[1], "rb").read(), sys.argv[1])
  234.     attrs = sc.GetSyntaxColorAttributes()
  235.     attrlen = 0
  236.     for attr in attrs:
  237.         if type(attr)==type(()):
  238.             attrlen = attrlen + attr[1]
  239.         else:
  240.             attrlen = attrlen + 1
  241.     text = sc.GetText()
  242.     if attrlen!=len(text):
  243.         print "Lengths dont match!!! (%d/%d)" % (attrlen, len(text))
  244.     
  245. #    print "Attributes:"
  246. #    print attrs
  247.     print "GetLineOfPos=", sc.GetLineOfPosition(0)
  248.     print "GetLineOfPos=", sc.GetLineOfPosition(4)
  249.     print "GetLineOfPos=", sc.GetLineOfPosition(10)