Instantly share code, notes, and snippets.
Created
May 15, 2014 06:24
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save yamaya/5d52b9b82c02c9be8625 to your computer and use it in GitHub Desktop.
generate ctags file using clang cindex.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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