def GenerateTags(buff): """Create a DocStruct object that represents a Shell Script @param buff: a file like buffer object (StringIO) """ rtags = taglib.DocStruct() rtags.SetElementDescription('function', "Function Definitions") for lnum, line in enumerate(buff): line = line.strip() # Skip comment and empty lines if line.startswith(u"#") or not line: continue # Check Regular Function Defs if parselib.IsToken(line, 0, u'function'): parts = line.split() plen = len(parts) if plen >= 2 and parselib.IsGoodName(parts[1]): if plen == 2 or parts[2] == u"{": rtags.AddFunction(taglib.Function(parts[1], lnum)) continue # Check fname () function defs if u"(" in line: parts = line.split() plen = len(parts) if plen >= 2 and parselib.IsGoodName(parts[0]): if u''.join(parts[1:]).startswith("()"): rtags.AddFunction(taglib.Function(parts[0], lnum)) else: continue return rtags
def GenerateTags(buff): """Create a DocStruct object that represents a Python file @param buff: a file like buffer object (StringIO) """ rtags = taglib.DocStruct() rtags.SetElementDescription('function', "Function Definitions") rtags.SetElementDescription('class', "Class Definitions") # Variables for managing the state of the parse parents = list() indent = 0 fn_indent = 0 parens = 0 # Paren nesting count indocstring = False ind_string = False # Double quote string ins_string = False # Single quote string infunction = False lastclass = None def NotInString(): """Return whether the current state of the parse is in a string or not. """ return not indocstring and not ind_string and not ins_string # Do the parse of the text for lnum, line in enumerate(buff): indent = 0 idx = 0 llen = len(line) while idx < llen: # Check for docstrings if not (ind_string or ins_string) and llen >= idx + 3 and line[idx:idx + 3] in [ '"""', "'''" ]: indocstring = not indocstring idx += 3 continue # If end of line or start of comment start next line if idx == llen or (line[idx] == u"#" and NotInString()): break # Check indent sensitive tokens if not indocstring and not line[idx].isspace(): if infunction and indent < fn_indent: infunction = False if lastclass is not None: if indent <= lastclass.get('indent', 0): parents = PopScopes(parents, indent) if len(parents): lastclass = parents[-1] else: lastclass = None # Check for if in a string or not if line[idx] == u"'" and not ind_string and \ idx > 0 and line[idx-1] != "\\": # Single string ins_string = not ins_string idx += 1 elif line[idx] == u'"' and not ins_string and \ idx > 0 and line[idx-1] != "\\": # Double String ind_string = not ind_string idx += 1 else: pass # Parse and look for elements to add to the DocStruct if not NotInString(): # Token is in a string so ignore and move on idx = idx + 1 elif line[idx].isspace(): # Get indent width for current scope if idx == 0: indent = (len(line) - len(line.lstrip())) idx += indent else: # Non indent space idx += 1 elif parselib.IsToken(line, idx, u'class'): idx += 5 cname = parselib.GetFirstIdentifier(line[idx:]) if cname is not None: if lastclass is None: rtags.AddClass(taglib.Class(cname, lnum)) # TODO: check for classes defined within classes lastclass = dict(name=cname, indent=indent) parents.append(dict(lastclass)) break # Go to next line elif parselib.IsToken(line, idx, u'def'): # Function/Method Definition idx += 3 fname = parselib.GetFirstIdentifier(line[idx:]) if line[idx].isspace() and fname is not None: infunction = True fn_indent = indent + 1 if not line[0].isspace() or lastclass is None or \ not len(lastclass.get("name", "")): rtags.AddFunction(taglib.Function(fname, lnum)) else: lclass = rtags.GetLastClass() if lclass is not None: lclass.AddMethod( taglib.Method(fname, lnum, lclass.GetName())) else: # Something must have failed with the parse so # ignore this element. pass break elif not infunction and line[idx] in u"()": # Track paren nesting to help with variable parsing if line[idx] == u"(": parens += 1 else: parens -= 1 idx += 1 elif not infunction and line[idx] == u"=" and not parens: # Check for Global and Class variables idx += 1 if line[idx] != u"=": # ignore == statements var = line[:idx - 1].strip().split() if len(var) == 1 and parselib.IsGoodName(var[0]): lclass = rtags.GetLastClass() # Check if we are still inside a class def or not if lastclass is not None and lclass is not None: vobj = taglib.Variable(var[0], lnum, lclass.GetName()) lclass.AddVariable(vobj) else: # Global Scope variable rtags.AddVariable(taglib.Variable(var[0], lnum)) else: # Nothing so skip ahead idx += 1 # Return the document structure object return rtags