Package moap :: Package util :: Module ctags
[hide private]
[frames] | no frames]

Source Code for Module moap.util.ctags

  1  # -*- Mode: Python; test-case-name: moap.test.test_util_ctags -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  """ 
  5  Code to parse ctags files. 
  6  """ 
  7   
  8  import re 
  9   
 10  from moap.util import log 
 11   
 12  # see man ctags, TAG FILE FORMAT 
 13  tagMatcher = re.compile('^(.+)\t(\S+)\t(.*);"\t(.*)') 
 14   
15 -class Tag:
16 """ 17 I represent one line in a ctags file. 18 """ 19 name = None 20 file = None 21 line = None 22 language = None 23 klazz = None 24
25 - def __repr__(self):
26 return "<Tag %s in file %s>" % (self.name, self.file)
27
28 - def parse(self, line):
29 """ 30 Parse a CTags line and set myself from it. 31 """ 32 # example of CTags lines: 33 # pads_cookie gst/gstelement.h /^ guint32 pads_cookie;$/;" m line:438 language:C++ struct:_GstElement 34 # target_state gst/gstelement.h /^ GstState target_state;$/;" m line:444 language:C++ struct:_GstElement::<anonymous>::<anonymous> 35 36 m = tagMatcher.search(line) 37 if not m: 38 raise KeyError, "line %s not a ctags line" % line 39 self.name = m.expand('\\1') 40 self.file = m.expand('\\2') 41 extended = m.expand('\\4') 42 for ext in extended.split(): 43 tags = ext.split(':') 44 # ignore one letter indications that do not have : 45 if len(tags) == 1: 46 continue 47 key = tags[0] 48 value = tags[1] 49 if key == 'line': 50 self.line = int(value) 51 elif key == 'language': 52 self.language = value 53 elif key == 'class': 54 self.klazz = value
55
56 -class CTags(log.Loggable):
57 logCategory = "CTags" 58
59 - def __init__(self):
60 self._files = {} # path -> dict of line number -> tag
61
62 - def addFile(self, path):
63 """ 64 Parse tags from the given file and add. 65 """ 66 handle = open(path, "r") 67 self._parse(handle.readlines())
68
69 - def addString(self, string):
70 if not string: 71 return 72 self._parse(string.split('\n'))
73
74 - def _parse(self, lines):
75 for line in lines: 76 if line.startswith('!_TAG_'): 77 continue 78 # see ticket #275 79 if line.startswith('ctags: Warning: ignoring null tag'): 80 continue 81 82 t = Tag() 83 t.parse(line) 84 if not self._files.has_key(t.file): 85 self._files[t.file] = {} 86 self._files[t.file][t.line] = t
87
88 - def getTags(self, file, line, count=1):
89 """ 90 Get all tags for the given file, starting at the given line number, 91 covered by the given count of lines from that point. 92 93 @returns: list of L{Tag} 94 """ 95 ret = [] 96 if count < 1: 97 return ret 98 99 tags = self._files[file] 100 starts = tags.keys() 101 starts.sort() 102 i = 0 103 # look for the tag right before the given line number 104 while tags[starts[i]].line <= line: 105 i += 1 106 if i == len(starts): 107 # line number is past the last tag, so we only return 108 # the last tag 109 self.debug('Returning only tag starting on %d' % starts[-1]) 110 return [tags[starts[-1]], ] 111 112 # now i points to a tag on or beyond the given line number, so go back 113 # one 114 i -= 1 115 116 if i >= 0: 117 # there is in fact a tag started before the given line, so append it 118 startLine = starts[i] 119 t = tags[startLine] 120 self.debug('appending tag for %s starting on line %d' % ( 121 t.name, startLine)) 122 ret.append(t) 123 124 # now we go back to the first tag starting on or past the given line 125 # number 126 i += 1 127 128 # now find all tags in the given range and append 129 # it is possible we are already past the end of starts 130 while count > 1 and tags[starts[i]].line < line + count: 131 startLine = starts[i] 132 t = tags[startLine] 133 self.debug('appending tag for %s starting on line %d' % ( 134 t.name, startLine)) 135 ret.append(t) 136 i += 1 137 if i == len(starts): 138 break 139 140 self.debug('returning %d tags' % len(ret)) 141 return ret
142