-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathctags.py
155 lines (139 loc) · 4.85 KB
/
ctags.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import os
import subprocess
import shlex
def get_ctags_version(executable=None):
"""
Return the text output from the --version option to ctags or None if ctags
executable cannot be found. Use executable for custom ctags builds and/or
path.
"""
args = shlex.split("ctags --version")
try:
p = subprocess.Popen(args, 0, shell=False, stdout=subprocess.PIPE, executable=executable)
version = p.communicate()[0]
except:
version = None
return version
class Tag(object):
"""
Represents a ctags "tag" found in some source code.
"""
def __init__(self, name):
self.name = name
self.file = None
self.ex_command = None
self.kind = None
self.fields = {}
class Kind(object):
"""
Represents a ctags "kind" found in some source code such as "member" or
"class".
"""
def __init__(self, name):
self.name = name
self.language = None
def group_name(self):
"""
Return the kind name as a group name. For example, 'variable' would
be 'Variables'. Pluralization is complex but this method is not. It
works more often than not.
"""
group = self.name
if self.name[-1] == 's':
group += 'es'
elif self.name[-1] == 'y':
group = self.name[0:-1] + 'ies'
else:
group += 's'
return group.capitalize()
def icon_name(self):
"""
Return the icon name in the form of 'source-<kind>'.
"""
return 'source-' + self.name
class Parser(object):
"""
Ctags Parser
Parses the output of a ctags command into a list of tags and a dictionary
of kinds.
"""
def has_kind(self, kind_name):
"""
Return true if kind_name is found in the list of kinds.
"""
if kind_name in self.kinds:
return True
else:
return False
def __init__(self):
self.tags = []
self.kinds = {}
self.tree = {}
def parse(self, command, executable=None):
"""
Parse ctags tags from the output of a ctags command. For example:
ctags -n --fields=fiKmnsSzt -f - some_file.php
"""
#args = [arg.replace('%20', ' ') for arg in shlex.split(command)]
args = shlex.split(command)
p = subprocess.Popen(args, 0, shell=False, stdout=subprocess.PIPE, executable=executable)
symbols = self._parse_text(p.communicate()[0])
def _parse_text(self, text):
"""
Parses ctags text which may have come from a TAG file or from raw output
from a ctags command.
"""
#print(str(text, 'utf-8'))
for line in text.splitlines():
name = None
file = None
ex_command = None
kind = None
for i, f in enumerate(line.split(b'\t')):
# print(i, f)
field = str(f, 'utf-8')
if i == 0: tag = Tag(field)
elif i == 1: tag.file = field
elif i == 2: tag.ex_command = field
elif i > 2:
if ":" in field:
key, value = field.split(":")[0:2]
tag.fields[key] = value
if key == 'kind':
kind = Kind(value)
if not kind in self.kinds:
self.kinds[value] = kind
if kind is not None:
if 'language' in tag.fields:
kind.language = tag.fields['language']
tag.kind = kind
self.tags.append(tag)
"""
def get_tree(self):
tree = {}
for tag in self.tags:
if 'class' in tag.fields:
parent = tag.fields['class']
if "." in parent:
parents = parent.split(".")
node = tree
for p in parents:
if not p in node:
node[p] = {'tag':None, 'children':{}}
node = node[p]
print(node)
node['tag'] = tag
else:
if not parent in self.tree:
tree[parent] = {'tag':None, 'children':{}}
tree[parent]['children'][tag.name] = {'tag':tag, 'children':{}}
else:
if tag.name in self.tree:
tree[tag.name]['tag'] = tag
else:
tree[tag.name] = {'tag': tag, 'children':{}}
return tree
"""
if __name__ == "__main__":
the_parser = Parser()
the_parser.parse("ctags -nu --fields=fiKlmnsSzt -f - ctags.py", "ctags")