-
Notifications
You must be signed in to change notification settings - Fork 291
Expand file tree
/
Copy pathsymbols.py
More file actions
157 lines (138 loc) · 5.3 KB
/
symbols.py
File metadata and controls
157 lines (138 loc) · 5.3 KB
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
156
157
# Copyright 2017 Palantir Technologies, Inc.
import logging
from pyls import hookimpl
from pyls.lsp import SymbolKind
log = logging.getLogger(__name__)
@hookimpl
def pyls_document_symbols(config, document):
useHierarchicalSymbols = config.plugin_settings('jedi_symbols').get('hierarchical_symbols', None)
if useHierarchicalSymbols is None:
useHierarchicalSymbols = (config.capabilities
.get("textDocument", {})
.get("documentSymbol", {})
.get("hierarchicalDocumentSymbolSupport", False))
if not useHierarchicalSymbols:
return pyls_document_symbols_legacy(config, document)
# returns DocumentSymbol[]
hide_imports = config.plugin_settings('jedi_symbols').get('hide_imports', False)
definitions = document.jedi_names(all_scopes=False)
def transform(d):
include_d = _include_def(d, hide_imports)
if include_d is None:
return None
children = [dt for dt in (transform(d1) for d1 in d.defined_names()) if dt] if include_d else None
detailName = d.full_name
if detailName and detailName.startswith("__main__."):
detailName = detailName[9:]
return {
'name': d.name,
'detail': detailName,
'range': _range(d),
'selectionRange': _name_range(d),
'kind': _kind(d),
'children': children
}
return [dt for dt in (transform(d) for d in definitions) if dt]
def pyls_document_symbols_legacy(config, document):
# returns SymbolInformation[]
all_scopes = config.plugin_settings('jedi_symbols').get('all_scopes', True)
hide_imports = config.plugin_settings('jedi_symbols').get('hide_imports', False)
definitions = document.jedi_names(all_scopes=all_scopes)
return [{
'name': d.name,
'containerName': _container(d),
'location': {
'uri': document.uri,
'range': _range(d),
},
'kind': _kind(d),
} for d in definitions if _include_def(d, hide_imports) is not None]
def _include_def(definition, hide_imports=True):
# returns
# True: include def and sub-defs
# False: include def but do not include sub-defs
# None: Do not include def or sub-defs
if ( # Unused vars should also be skipped
definition.name != '_' and
definition.is_definition() and
not definition.in_builtin_module() and
_kind(definition) is not None
):
if definition._name.is_import():
return None if hide_imports else False
# for `statement`, we do not enumerate its child nodes. It tends to cause Error.
return definition.type not in ("statement",)
return None
def _container(definition):
try:
# Jedi sometimes fails here.
parent = definition.parent()
# Here we check that a grand-parent exists to avoid declaring symbols
# as children of the module.
if parent.parent():
return parent.name
except: # pylint: disable=bare-except
return None
return None
def _range(definition):
# This gets us more accurate end position
definition = definition._name.tree_name.get_definition()
(start_line, start_column) = definition.start_pos
(end_line, end_column) = definition.end_pos
return {
'start': {'line': start_line - 1, 'character': start_column},
'end': {'line': end_line - 1, 'character': end_column}
}
def _name_range(definition):
# Gets the range of symbol name (e.g. function name of a function)
definition = definition._name.tree_name
(start_line, start_column) = definition.start_pos
(end_line, end_column) = definition.end_pos
return {
'start': {'line': start_line - 1, 'character': start_column},
'end': {'line': end_line - 1, 'character': end_column}
}
_SYMBOL_KIND_MAP = {
'none': SymbolKind.Variable,
'type': SymbolKind.Class,
'tuple': SymbolKind.Class,
'dict': SymbolKind.Class,
'dictionary': SymbolKind.Class,
'function': SymbolKind.Function,
'lambda': SymbolKind.Function,
'generator': SymbolKind.Function,
'class': SymbolKind.Class,
'instance': SymbolKind.Class,
'method': SymbolKind.Method,
'builtin': SymbolKind.Class,
'builtinfunction': SymbolKind.Function,
'module': SymbolKind.Module,
'file': SymbolKind.File,
'xrange': SymbolKind.Array,
'slice': SymbolKind.Class,
'traceback': SymbolKind.Class,
'frame': SymbolKind.Class,
'buffer': SymbolKind.Array,
'dictproxy': SymbolKind.Class,
'funcdef': SymbolKind.Function,
'property': SymbolKind.Property,
'import': SymbolKind.Module,
'keyword': SymbolKind.Variable,
'constant': SymbolKind.Constant,
'variable': SymbolKind.Variable,
'value': SymbolKind.Variable,
# Don't tend to include parameters as symbols
# 'param': SymbolKind.Variable,
'statement': SymbolKind.Variable,
'boolean': SymbolKind.Boolean,
'int': SymbolKind.Number,
'longlean': SymbolKind.Number,
'float': SymbolKind.Number,
'complex': SymbolKind.Number,
'string': SymbolKind.String,
'unicode': SymbolKind.String,
'list': SymbolKind.Array,
}
def _kind(d):
""" Return the VSCode Symbol Type """
return _SYMBOL_KIND_MAP.get(d.type)