Skip to content

Commit 95c9598

Browse files
committed
Emit nested document symbols.
The change in #629 moved to a non-deprecated representation of document symbol. The new representation is the "Ikea" version of the old one, where children symbol are not computed for you, but need to be provided. This PR computes and emits the tree of symbols using the `children` field.
1 parent e9853d5 commit 95c9598

File tree

4 files changed

+173
-108
lines changed

4 files changed

+173
-108
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545

4646
- Fix issue where jump to definition would go to the wrong place when there are aliased identifiers in submodules https://github.com/rescript-lang/rescript-vscode/pull/653
4747

48+
- Fix issue where document symbols were not shown nested
49+
4850
## v1.8.2
4951

5052
#### :rocket: New Feature

analysis/src/DocumentSymbol.ml

+69-20
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ let kindNumber = function
2626

2727
let command ~path =
2828
let symbols = ref [] in
29+
let addSymbol name loc kind =
30+
let range = Utils.cmtLocToRange loc in
31+
let symbol : Protocol.documentSymbolItem =
32+
{name; range; kind = kindNumber kind; children = []}
33+
in
34+
symbols := symbol :: !symbols
35+
in
2936
let rec exprKind (exp : Parsetree.expression) =
3037
match exp.pexp_desc with
3138
| Pexp_fun _ -> Function
@@ -41,43 +48,41 @@ let command ~path =
4148
| Ptype_variant constrDecls ->
4249
constrDecls
4350
|> List.iter (fun (cd : Parsetree.constructor_declaration) ->
44-
symbols := (cd.pcd_name.txt, cd.pcd_loc, EnumMember) :: !symbols)
51+
addSymbol cd.pcd_name.txt cd.pcd_loc EnumMember)
4552
| Ptype_record labelDecls ->
4653
labelDecls
4754
|> List.iter (fun (ld : Parsetree.label_declaration) ->
48-
symbols := (ld.pld_name.txt, ld.pld_loc, Property) :: !symbols)
55+
addSymbol ld.pld_name.txt ld.pld_loc Property)
4956
| _ -> ()
5057
in
5158
let processTypeDeclaration (td : Parsetree.type_declaration) =
52-
symbols := (td.ptype_name.txt, td.ptype_loc, TypeParameter) :: !symbols;
59+
addSymbol td.ptype_name.txt td.ptype_loc TypeParameter;
5360
processTypeKind td.ptype_kind
5461
in
5562
let processValueDescription (vd : Parsetree.value_description) =
56-
symbols := (vd.pval_name.txt, vd.pval_loc, Variable) :: !symbols
63+
addSymbol vd.pval_name.txt vd.pval_loc Variable
5764
in
5865
let processModuleBinding (mb : Parsetree.module_binding) =
59-
symbols := (mb.pmb_name.txt, mb.pmb_loc, Module) :: !symbols
66+
addSymbol mb.pmb_name.txt mb.pmb_loc Module
6067
in
6168
let processModuleDeclaration (md : Parsetree.module_declaration) =
62-
symbols := (md.pmd_name.txt, md.pmd_loc, Module) :: !symbols
69+
addSymbol md.pmd_name.txt md.pmd_loc Module
6370
in
6471
let processExtensionConstructor (et : Parsetree.extension_constructor) =
65-
symbols := (et.pext_name.txt, et.pext_loc, Constructor) :: !symbols
72+
addSymbol et.pext_name.txt et.pext_loc Constructor
6673
in
6774
let value_binding (iterator : Ast_iterator.iterator)
6875
(vb : Parsetree.value_binding) =
6976
(match vb.pvb_pat.ppat_desc with
7077
| Ppat_var {txt} | Ppat_constraint ({ppat_desc = Ppat_var {txt}}, _) ->
71-
symbols := (txt, vb.pvb_loc, exprKind vb.pvb_expr) :: !symbols
78+
addSymbol txt vb.pvb_loc (exprKind vb.pvb_expr)
7279
| _ -> ());
7380
Ast_iterator.default_iterator.value_binding iterator vb
7481
in
7582
let expr (iterator : Ast_iterator.iterator) (e : Parsetree.expression) =
7683
(match e.pexp_desc with
7784
| Pexp_letmodule ({txt}, modExpr, _) ->
78-
symbols :=
79-
(txt, {e.pexp_loc with loc_end = modExpr.pmod_loc.loc_end}, Module)
80-
:: !symbols
85+
addSymbol txt {e.pexp_loc with loc_end = modExpr.pmod_loc.loc_end} Module
8186
| Pexp_letexception (ec, _) -> processExtensionConstructor ec
8287
| _ -> ());
8388
Ast_iterator.default_iterator.expr iterator e
@@ -134,12 +139,56 @@ let command ~path =
134139
let parser = Res_driver.parsingEngine.parseInterface ~forPrinter:false in
135140
let {Res_driver.parsetree = signature} = parser ~filename:path in
136141
iterator.signature iterator signature |> ignore);
137-
let result =
138-
!symbols
139-
|> List.rev_map (fun (name, loc, kind) ->
140-
let range = Utils.cmtLocToRange loc in
141-
Protocol.stringifyDocumentSymbolItem
142-
{name; range; selectionRange = range; kind = kindNumber kind})
143-
|> String.concat ",\n"
144-
in
145-
print_endline ("[\n" ^ result ^ "\n]")
142+
let isInside
143+
({
144+
range =
145+
{
146+
start = {line = sl1; character = sc1};
147+
end_ = {line = el1; character = ec1};
148+
};
149+
} :
150+
Protocol.documentSymbolItem)
151+
({
152+
range =
153+
{
154+
start = {line = sl2; character = sc2};
155+
end_ = {line = el2; character = ec2};
156+
};
157+
} :
158+
Protocol.documentSymbolItem) =
159+
(sl1 > sl2 || (sl1 = sl2 && sc1 >= sc2))
160+
&& (el1 < el2 || (el1 = el2 && ec1 <= ec2))
161+
in
162+
let compareSymbol (s1 : Protocol.documentSymbolItem)
163+
(s2 : Protocol.documentSymbolItem) =
164+
let n = compare s1.range.start.line s2.range.start.line in
165+
if n <> 0 then n
166+
else
167+
let n = compare s1.range.start.character s2.range.start.character in
168+
if n <> 0 then n
169+
else
170+
let n = compare s1.range.end_.line s2.range.end_.line in
171+
if n <> 0 then n
172+
else compare s1.range.end_.character s2.range.end_.character
173+
in
174+
let rec addSymbolToChildren children symbol =
175+
match children with
176+
| [] -> [symbol]
177+
| last :: rest ->
178+
if isInside symbol last then
179+
let newLast =
180+
{last with children = addSymbolToChildren last.children symbol}
181+
in
182+
newLast :: rest
183+
else symbol :: children
184+
in
185+
let rec addSortedSymbolsToChildren ~sortedSymbols children =
186+
match sortedSymbols with
187+
| [] -> children
188+
| firstSymbol :: rest ->
189+
let newChildren = addSymbolToChildren children firstSymbol in
190+
addSortedSymbolsToChildren ~sortedSymbols:rest newChildren
191+
in
192+
let sortedSymbols = !symbols |> List.sort compareSymbol in
193+
let symbolsWithChildren = [] |> addSortedSymbolsToChildren ~sortedSymbols in
194+
print_endline (Protocol.stringifyDocumentSymbolItems symbolsWithChildren)

analysis/src/Protocol.ml

+25-8
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type documentSymbolItem = {
4646
name: string;
4747
kind: int;
4848
range: range;
49-
selectionRange: range;
49+
children: documentSymbolItem list;
5050
}
5151
type renameFile = {oldUri: string; newUri: string}
5252
type textEdit = {range: range; newText: string}
@@ -102,22 +102,39 @@ let stringifyCompletionItem c =
102102
| None -> null
103103
| Some doc -> stringifyMarkupContent doc)
104104

105-
let stringifyHover value = Printf.sprintf {|{"contents": %s}|} (stringifyMarkupContent {kind = "markdown"; value})
105+
let stringifyHover value =
106+
Printf.sprintf {|{"contents": %s}|}
107+
(stringifyMarkupContent {kind = "markdown"; value})
106108

107109
let stringifyLocation (h : location) =
108110
Printf.sprintf {|{"uri": "%s", "range": %s}|} (Json.escape h.uri)
109111
(stringifyRange h.range)
110112

111-
let stringifyDocumentSymbolItem (i : documentSymbolItem) =
113+
let rec stringifyDocumentSymbolItem (i : documentSymbolItem) =
112114
let range = stringifyRange i.range in
115+
let children =
116+
if i.children = [] then ""
117+
else
118+
Printf.sprintf {|,
119+
"children": [%s]|}
120+
(i.children
121+
|> List.rev_map stringifyDocumentSymbolItem
122+
|> String.concat ", ")
123+
in
113124
Printf.sprintf
114125
{|{
115-
"name": "%s",
116-
"kind": %i,
117-
"range": %s,
118-
"selectionRange": %s
126+
"name": "%s",
127+
"kind": %i,
128+
"range": %s,
129+
"selectionRange": %s%s
119130
}|}
120-
(Json.escape i.name) i.kind range range
131+
(Json.escape i.name) i.kind range range children
132+
133+
let stringifyDocumentSymbolItems items =
134+
let result =
135+
items |> List.rev_map stringifyDocumentSymbolItem |> String.concat ",\n"
136+
in
137+
"[\n" ^ result ^ "\n]"
121138

122139
let stringifyRenameFile {oldUri; newUri} =
123140
Printf.sprintf {|{
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,97 @@
11
DocumentSymbol src/DocumentSymbol.res
22
[
33
{
4-
"name": "MyList",
5-
"kind": 2,
6-
"range": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 25}},
7-
"selectionRange": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 25}}
4+
"name": "MyList",
5+
"kind": 2,
6+
"range": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 25}},
7+
"selectionRange": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 25}}
88
},
99
{
10-
"name": "Dep",
11-
"kind": 2,
12-
"range": {"start": {"line": 2, "character": 7}, "end": {"line": 7, "character": 1}},
13-
"selectionRange": {"start": {"line": 2, "character": 7}, "end": {"line": 7, "character": 1}}
10+
"name": "Dep",
11+
"kind": 2,
12+
"range": {"start": {"line": 2, "character": 7}, "end": {"line": 7, "character": 1}},
13+
"selectionRange": {"start": {"line": 2, "character": 7}, "end": {"line": 7, "character": 1}},
14+
"children": [{
15+
"name": "customDouble",
16+
"kind": 12,
17+
"range": {"start": {"line": 6, "character": 2}, "end": {"line": 6, "character": 35}},
18+
"selectionRange": {"start": {"line": 6, "character": 2}, "end": {"line": 6, "character": 35}}
19+
}]
1420
},
1521
{
16-
"name": "customDouble",
17-
"kind": 12,
18-
"range": {"start": {"line": 6, "character": 2}, "end": {"line": 6, "character": 35}},
19-
"selectionRange": {"start": {"line": 6, "character": 2}, "end": {"line": 6, "character": 35}}
22+
"name": "Lib",
23+
"kind": 2,
24+
"range": {"start": {"line": 9, "character": 7}, "end": {"line": 12, "character": 1}},
25+
"selectionRange": {"start": {"line": 9, "character": 7}, "end": {"line": 12, "character": 1}},
26+
"children": [{
27+
"name": "foo",
28+
"kind": 12,
29+
"range": {"start": {"line": 10, "character": 2}, "end": {"line": 10, "character": 55}},
30+
"selectionRange": {"start": {"line": 10, "character": 2}, "end": {"line": 10, "character": 55}}
31+
}, {
32+
"name": "next",
33+
"kind": 12,
34+
"range": {"start": {"line": 11, "character": 2}, "end": {"line": 11, "character": 48}},
35+
"selectionRange": {"start": {"line": 11, "character": 2}, "end": {"line": 11, "character": 48}}
36+
}]
2037
},
2138
{
22-
"name": "Lib",
23-
"kind": 2,
24-
"range": {"start": {"line": 9, "character": 7}, "end": {"line": 12, "character": 1}},
25-
"selectionRange": {"start": {"line": 9, "character": 7}, "end": {"line": 12, "character": 1}}
39+
"name": "op",
40+
"kind": 13,
41+
"range": {"start": {"line": 14, "character": 0}, "end": {"line": 14, "character": 16}},
42+
"selectionRange": {"start": {"line": 14, "character": 0}, "end": {"line": 14, "character": 16}}
2643
},
2744
{
28-
"name": "foo",
29-
"kind": 12,
30-
"range": {"start": {"line": 10, "character": 2}, "end": {"line": 10, "character": 55}},
31-
"selectionRange": {"start": {"line": 10, "character": 2}, "end": {"line": 10, "character": 55}}
45+
"name": "ForAuto",
46+
"kind": 2,
47+
"range": {"start": {"line": 16, "character": 7}, "end": {"line": 20, "character": 1}},
48+
"selectionRange": {"start": {"line": 16, "character": 7}, "end": {"line": 20, "character": 1}},
49+
"children": [{
50+
"name": "t",
51+
"kind": 26,
52+
"range": {"start": {"line": 17, "character": 2}, "end": {"line": 17, "character": 14}},
53+
"selectionRange": {"start": {"line": 17, "character": 2}, "end": {"line": 17, "character": 14}}
54+
}, {
55+
"name": "abc",
56+
"kind": 12,
57+
"range": {"start": {"line": 18, "character": 2}, "end": {"line": 18, "character": 32}},
58+
"selectionRange": {"start": {"line": 18, "character": 2}, "end": {"line": 18, "character": 32}}
59+
}, {
60+
"name": "abd",
61+
"kind": 12,
62+
"range": {"start": {"line": 19, "character": 2}, "end": {"line": 19, "character": 32}},
63+
"selectionRange": {"start": {"line": 19, "character": 2}, "end": {"line": 19, "character": 32}}
64+
}]
3265
},
3366
{
34-
"name": "next",
35-
"kind": 12,
36-
"range": {"start": {"line": 11, "character": 2}, "end": {"line": 11, "character": 48}},
37-
"selectionRange": {"start": {"line": 11, "character": 2}, "end": {"line": 11, "character": 48}}
67+
"name": "fa",
68+
"kind": 16,
69+
"range": {"start": {"line": 22, "character": 0}, "end": {"line": 22, "character": 22}},
70+
"selectionRange": {"start": {"line": 22, "character": 0}, "end": {"line": 22, "character": 22}}
3871
},
3972
{
40-
"name": "op",
41-
"kind": 13,
42-
"range": {"start": {"line": 14, "character": 0}, "end": {"line": 14, "character": 16}},
43-
"selectionRange": {"start": {"line": 14, "character": 0}, "end": {"line": 14, "character": 16}}
73+
"name": "O",
74+
"kind": 2,
75+
"range": {"start": {"line": 24, "character": 7}, "end": {"line": 29, "character": 1}},
76+
"selectionRange": {"start": {"line": 24, "character": 7}, "end": {"line": 29, "character": 1}},
77+
"children": [{
78+
"name": "Comp",
79+
"kind": 2,
80+
"range": {"start": {"line": 25, "character": 9}, "end": {"line": 28, "character": 3}},
81+
"selectionRange": {"start": {"line": 25, "character": 9}, "end": {"line": 28, "character": 3}},
82+
"children": [{
83+
"name": "make",
84+
"kind": 12,
85+
"range": {"start": {"line": 27, "character": 4}, "end": {"line": 27, "character": 98}},
86+
"selectionRange": {"start": {"line": 27, "character": 4}, "end": {"line": 27, "character": 98}}
87+
}]
88+
}]
4489
},
4590
{
46-
"name": "ForAuto",
47-
"kind": 2,
48-
"range": {"start": {"line": 16, "character": 7}, "end": {"line": 20, "character": 1}},
49-
"selectionRange": {"start": {"line": 16, "character": 7}, "end": {"line": 20, "character": 1}}
50-
},
51-
{
52-
"name": "t",
53-
"kind": 26,
54-
"range": {"start": {"line": 17, "character": 2}, "end": {"line": 17, "character": 14}},
55-
"selectionRange": {"start": {"line": 17, "character": 2}, "end": {"line": 17, "character": 14}}
56-
},
57-
{
58-
"name": "abc",
59-
"kind": 12,
60-
"range": {"start": {"line": 18, "character": 2}, "end": {"line": 18, "character": 32}},
61-
"selectionRange": {"start": {"line": 18, "character": 2}, "end": {"line": 18, "character": 32}}
62-
},
63-
{
64-
"name": "abd",
65-
"kind": 12,
66-
"range": {"start": {"line": 19, "character": 2}, "end": {"line": 19, "character": 32}},
67-
"selectionRange": {"start": {"line": 19, "character": 2}, "end": {"line": 19, "character": 32}}
68-
},
69-
{
70-
"name": "fa",
71-
"kind": 16,
72-
"range": {"start": {"line": 22, "character": 0}, "end": {"line": 22, "character": 22}},
73-
"selectionRange": {"start": {"line": 22, "character": 0}, "end": {"line": 22, "character": 22}}
74-
},
75-
{
76-
"name": "O",
77-
"kind": 2,
78-
"range": {"start": {"line": 24, "character": 7}, "end": {"line": 29, "character": 1}},
79-
"selectionRange": {"start": {"line": 24, "character": 7}, "end": {"line": 29, "character": 1}}
80-
},
81-
{
82-
"name": "Comp",
83-
"kind": 2,
84-
"range": {"start": {"line": 25, "character": 9}, "end": {"line": 28, "character": 3}},
85-
"selectionRange": {"start": {"line": 25, "character": 9}, "end": {"line": 28, "character": 3}}
86-
},
87-
{
88-
"name": "make",
89-
"kind": 12,
90-
"range": {"start": {"line": 27, "character": 4}, "end": {"line": 27, "character": 98}},
91-
"selectionRange": {"start": {"line": 27, "character": 4}, "end": {"line": 27, "character": 98}}
92-
},
93-
{
94-
"name": "zzz",
95-
"kind": 16,
96-
"range": {"start": {"line": 31, "character": 0}, "end": {"line": 31, "character": 12}},
97-
"selectionRange": {"start": {"line": 31, "character": 0}, "end": {"line": 31, "character": 12}}
91+
"name": "zzz",
92+
"kind": 16,
93+
"range": {"start": {"line": 31, "character": 0}, "end": {"line": 31, "character": 12}},
94+
"selectionRange": {"start": {"line": 31, "character": 0}, "end": {"line": 31, "character": 12}}
9895
}
9996
]
10097

0 commit comments

Comments
 (0)