Skip to content

Instantly share code, notes, and snippets.

@yamaya
Created May 15, 2014 06:24
Show Gist options
  • Select an option

  • Save yamaya/5d52b9b82c02c9be8625 to your computer and use it in GitHub Desktop.

Select an option

Save yamaya/5d52b9b82c02c9be8625 to your computer and use it in GitHub Desktop.
generate ctags file using clang cindex.py
#!/usr/bin/env python
from pprint import PrettyPrinter
pp = PrettyPrinter(width = 2048).pprint
def format_diagnostics(diag):
return {
'severity': diag.severity,
'location': diag.location,
'spelling': diag.spelling,
'ranges': diag.ranges,
'fixits': diag.fixits
}
def format_nodes_recursive(node, depth = 0):
children = [format_nodes_recursive(c, depth + 1) for c in node.get_children()]
return {
'kind': node.kind,
'usr': node.get_usr(),
'spelling': node.spelling,
'location': node.location,
'extent.start': node.extent.start,
'extent.end': node.extent.end,
'is_definition': node.is_definition(),
'children': children
}
_kind_to_field_map = None
def kind_to_field_map():
global _kind_to_field_map
if _kind_to_field_map is None:
from clang.cindex import CursorKind
_kind_to_field_map = {
CursorKind.OBJC_INTERFACE_DECL: 'c',
CursorKind.OBJC_CATEGORY_DECL: 'x',
CursorKind.OBJC_IMPLEMENTATION_DECL: 'I',
CursorKind.OBJC_CATEGORY_IMPL_DECL: 'I',
CursorKind.OBJC_PROTOCOL_DECL: 'P',
CursorKind.OBJC_INSTANCE_METHOD_DECL: 'm',
CursorKind.OBJC_CLASS_METHOD_DECL: 'm',
CursorKind.OBJC_PROPERTY_DECL: 'p',
CursorKind.OBJC_IVAR_DECL: 'p',
CursorKind.TYPEDEF_DECL: 't',
CursorKind.VAR_DECL: 'v',
CursorKind.ENUM_DECL: 'E',
CursorKind.ENUM_CONSTANT_DECL: 'e',
CursorKind.FUNCTION_DECL: 'f',
CursorKind.MACRO_DEFINITION: 'd',
CursorKind.STRUCT_DECL: 's',
CursorKind.UNION_DECL: 's',
CursorKind.CLASS_DECL: 'c',
CursorKind.FIELD_DECL: 'p',
CursorKind.CXX_METHOD: 'm',
CursorKind.CONSTRUCTOR: 'm',
CursorKind.DESTRUCTOR: 'm',
CursorKind.CONVERSION_FUNCTION: 'm',
CursorKind.FUNCTION_TEMPLATE: 'f',
CursorKind.CLASS_TEMPLATE: 'c',
CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: 'c',
CursorKind.NAMESPACE: 'n',
CursorKind.NAMESPACE_ALIAS: 'n',
CursorKind.TYPE_ALIAS_DECL: 't'
}
return _kind_to_field_map
def make_tag(node):
fmap = kind_to_field_map()
return format_tag(node, fmap.get(node.kind))
def detect_field(obj):
return None
_include_fileds = ['c', 'x', 'P', 't', 'v', 'e', 'f', 'd', 'c', 'f', 'n']
def format_tag(node, kind):
if kind is None or _include_fileds.count(kind) == 0:
return None
if node.location.file is None:
return None
spelling = node.spelling
if spelling is None or len(spelling) == 0:
spelling = None
if kind == 'd':
spelling = node.get_usr()
i = spelling.find('@')
if i != -1:
spelling = spelling[i + 1:]
if spelling is None:
return None
items = [
spelling,
node.location.file.name
]
with open(node.location.file.name, 'r') as file:
found = False
lno = node.location.line - 1
for i, line in enumerate(file):
found = (i == lno)
if found:
items.append('/^%s$/' % line[:-1])
break
assert found, 'Not found: spelling="%s", lineno=%d' % (spelling, lno)
return '%s;"\t%s' % ('\t'.join(items), kind)
def generate_tags(origin, tags):
for node in origin.get_children():
generate_tags(node, tags)
tag = make_tag(origin)
if tag:
tags.append(tag)
def main():
from clang.cindex import Index, TranslationUnit
from optparse import OptionParser, OptionGroup
global opts
op = OptionParser("usage: %prog [options] {filename} [clang-args*]")
op.disable_interspersed_args()
(opts, args) = op.parse_args()
if len(args) == 0:
op.error('invalid number arguments')
index = Index.create()
tu = index.parse(None, args, None, \
TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD | \
TranslationUnit.PARSE_INCOMPLETE | \
TranslationUnit.PARSE_SKIP_FUNCTION_BODIES)
if not tu:
op.error("unable to load input")
diags = tu.diagnostics
if diags and len(diags) != 0:
pp(('diags', map(format_diagnostics, tu.diagnostics)))
#pp(('nodes', format_nodes_recursive(tu.cursor)))
tags = []
generate_tags(tu.cursor, tags)
tags.sort()
header = '''!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //'''
print header
for tag in tags:
print tag
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment