Skip to content

Commit 9a3545d

Browse files
authored
Hierarchical symbols (palantir#176)
* Correctly structure outline view * Improve smybol spec to better show the behavior * Symbol hierarchies * Symbol hierarchies * Symbol hierarchies * Fixes * Fixes
1 parent 5370a8d commit 9a3545d

2 files changed

Lines changed: 47 additions & 16 deletions

File tree

pyls/plugins/symbols.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,45 @@ def pyls_document_symbols(config, document):
1212
definitions = document.jedi_names(all_scopes=all_scopes)
1313
return [{
1414
'name': d.name,
15+
'containerName': _container(d),
16+
'location': {
17+
'uri': document.uri,
18+
'range': _range(d),
19+
},
1520
'kind': _kind(d),
16-
'location': {'uri': document.uri, 'range': _range(d)}
17-
} for d in definitions]
21+
} for d in definitions if _include_def(d)]
1822

1923

20-
def _range(d):
24+
def _include_def(definition):
25+
return (
26+
# Don't tend to include parameters as symbols
27+
definition.type != 'param' and
28+
# Unused vars should also be skipped
29+
definition.name != '_' and
30+
_kind(definition) is not None
31+
)
32+
33+
34+
def _container(definition):
35+
try:
36+
# Jedi sometimes fails here.
37+
parent = definition.parent()
38+
# Here we check that a grand-parent exists to avoid declaring symbols
39+
# as children of the module.
40+
if parent.parent():
41+
return parent.name
42+
except:
43+
pass
44+
45+
46+
def _range(definition):
47+
# This gets us more accurate end position
48+
definition = definition._name.tree_name.get_definition()
49+
(start_line, start_column) = definition.start_pos
50+
(end_line, end_column) = definition.end_pos
2151
return {
22-
'start': {'line': d.line - 1, 'character': d.column},
23-
'end': {'line': d.line - 1, 'character': d.column + len(d.name)}
52+
'start': {'line': start_line - 1, 'character': start_column},
53+
'end': {'line': end_line - 1, 'character': end_column}
2454
}
2555

2656

test/plugins/test_symbols.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
a = 'hello'
1111
1212
class B:
13-
def __init__():
14-
pass
13+
def __init__(self):
14+
x = 2
15+
self.y = x
16+
17+
def main(x):
18+
y = 2 * x
19+
return y
1520
16-
def main():
17-
pass
1821
"""
1922

2023

@@ -23,14 +26,13 @@ def test_symbols(config):
2326
config.update({'plugins': {'jedi_symbols': {'all_scopes': False}}})
2427
symbols = pyls_document_symbols(config, doc)
2528

26-
# All four symbols (import sys, a, B, main)
27-
assert len(symbols) == 4
29+
# All four symbols (import sys, a, B, main, y)
30+
assert len(symbols) == 5
2831

2932
def sym(name):
3033
return [s for s in symbols if s['name'] == name][0]
3134

3235
# Check we have some sane mappings to VSCode constants
33-
assert sym('sys')['kind'] == SymbolKind.Module
3436
assert sym('a')['kind'] == SymbolKind.Variable
3537
assert sym('B')['kind'] == SymbolKind.Class
3638
assert sym('main')['kind'] == SymbolKind.Function
@@ -39,18 +41,17 @@ def sym(name):
3941
assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0}
4042

4143

42-
def test_symbols_alls_scopes(config):
44+
def test_symbols_all_scopes(config):
4345
doc = Document(DOC_URI, DOC)
4446
symbols = pyls_document_symbols(config, doc)
4547

46-
# All five symbols (import sys, a, B, __init__, main)
47-
assert len(symbols) == 5
48+
# All eight symbols (import sys, a, B, __init__, x, y, main, y)
49+
assert len(symbols) == 8
4850

4951
def sym(name):
5052
return [s for s in symbols if s['name'] == name][0]
5153

5254
# Check we have some sane mappings to VSCode constants
53-
assert sym('sys')['kind'] == SymbolKind.Module
5455
assert sym('a')['kind'] == SymbolKind.Variable
5556
assert sym('B')['kind'] == SymbolKind.Class
5657
assert sym('__init__')['kind'] == SymbolKind.Function

0 commit comments

Comments
 (0)