Skip to content

Commit 4bb8fae

Browse files
authored
feat(lsp): Goto type definition (#2129)
1 parent d4a99f9 commit 4bb8fae

File tree

12 files changed

+118
-70
lines changed

12 files changed

+118
-70
lines changed

compiler/src/language_server/driver.re

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ let process = msg => {
4646
| Formatting(id, params) when is_initialized^ =>
4747
Formatting.process(~id, ~compiled_code, ~documents, params);
4848
Reading;
49-
| Definition(id, params) when is_initialized^ =>
50-
Definition.process(~id, ~compiled_code, ~documents, params);
49+
| Goto(id, goto_request_type, params) when is_initialized^ =>
50+
Goto.process(~id, ~compiled_code, ~documents, goto_request_type, params);
5151
Reading;
5252
| SetTrace(trace_value) =>
5353
Trace.set_level(trace_value);

compiler/src/language_server/definition.re renamed to compiler/src/language_server/goto.re

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,27 @@ open Grain_diagnostics;
77
open Sourcetree;
88
open Lsp_types;
99

10+
type goto_request_type =
11+
| Definition
12+
| TypeDefinition;
13+
1014
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#definitionParams
1115
module RequestParams = {
1216
[@deriving yojson({strict: false})]
13-
type t = {
14-
[@key "textDocument"]
15-
text_document: Protocol.text_document_identifier,
16-
position: Protocol.position,
17-
};
17+
type t = Protocol.text_document_position_params;
1818
};
1919

2020
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#locationLink
2121
module ResponseResult = {
2222
[@deriving yojson]
23-
type t = {
24-
[@key "originSelectionRange"]
25-
origin_selection_range: Protocol.range,
26-
[@key "targetUri"]
27-
target_uri: Protocol.uri,
28-
[@key "targetRange"]
29-
target_range: Protocol.range,
30-
[@key "targetSelectionRange"]
31-
target_selection_range: Protocol.range,
32-
};
23+
type t = Protocol.location_link;
3324
};
3425

3526
let send_no_result = (~id: Protocol.message_id) => {
3627
Protocol.response(~id, `Null);
3728
};
3829

39-
let send_definition =
30+
let send_location_link =
4031
(
4132
~id: Protocol.message_id,
4233
~range: Protocol.range,
@@ -45,48 +36,43 @@ let send_definition =
4536
) => {
4637
Protocol.response(
4738
~id,
48-
ResponseResult.to_yojson({
39+
Protocol.location_link_to_yojson({
4940
origin_selection_range: range,
5041
target_uri,
5142
target_range,
5243
target_selection_range: target_range,
5344
}),
5445
);
5546
};
47+
5648
type check_position =
5749
| Forward
5850
| Backward;
59-
let rec find_definition =
51+
52+
let rec find_location =
6053
(
6154
~check_position=Forward,
55+
get_location: list(Sourcetree.node) => option(Location.t),
6256
sourcetree: Sourcetree.sourcetree,
6357
position: Protocol.position,
6458
) => {
6559
let results = Sourcetree.query(position, sourcetree);
6660

6761
let result =
68-
switch (results) {
69-
| [Value({definition}), ..._]
70-
| [Pattern({definition}), ..._]
71-
| [Type({definition}), ..._]
72-
| [Declaration({definition}), ..._]
73-
| [Exception({definition}), ..._]
74-
| [Module({definition}), ..._] =>
75-
switch (definition) {
76-
| None => None
77-
| Some(loc) =>
78-
let uri = Utils.filename_to_uri(loc.loc_start.pos_fname);
79-
Some((loc, uri));
80-
}
81-
| _ => None
62+
switch (get_location(results)) {
63+
| None => None
64+
| Some(loc) =>
65+
let uri = Utils.filename_to_uri(loc.loc_start.pos_fname);
66+
Some((loc, uri));
8267
};
8368
switch (result) {
8469
| None =>
8570
if (check_position == Forward && position.character > 0) {
8671
// If a user selects from left to right, their pointer ends up after the identifier
8772
// this tries to check if the identifier was selected.
88-
find_definition(
73+
find_location(
8974
~check_position=Backward,
75+
get_location,
9076
sourcetree,
9177
{line: position.line, character: position.character - 1},
9278
);
@@ -102,16 +88,44 @@ let process =
10288
~id: Protocol.message_id,
10389
~compiled_code: Hashtbl.t(Protocol.uri, Lsp_types.code),
10490
~documents: Hashtbl.t(Protocol.uri, string),
91+
goto_request_type: goto_request_type,
10592
params: RequestParams.t,
10693
) => {
10794
switch (Hashtbl.find_opt(compiled_code, params.text_document.uri)) {
10895
| None => send_no_result(~id)
10996
| Some({program, sourcetree}) =>
110-
let result = find_definition(sourcetree, params.position);
97+
let get_location =
98+
switch (goto_request_type) {
99+
| Definition => (
100+
results => {
101+
switch (results) {
102+
| [Sourcetree.Value({definition}), ..._]
103+
| [Pattern({definition}), ..._]
104+
| [Type({definition}), ..._]
105+
| [Declaration({definition}), ..._]
106+
| [Exception({definition}), ..._]
107+
| [Module({definition}), ..._] => definition
108+
| _ => None
109+
};
110+
}
111+
)
112+
| TypeDefinition => (
113+
results => {
114+
switch (results) {
115+
| [Value({env, value_type: type_expr}), ..._] =>
116+
Env.get_type_definition_loc(type_expr, env)
117+
| [Pattern({definition}), ..._] => definition
118+
| _ => None
119+
};
120+
}
121+
)
122+
};
123+
124+
let result = find_location(get_location, sourcetree, params.position);
111125
switch (result) {
112126
| None => send_no_result(~id)
113127
| Some((loc, uri)) =>
114-
send_definition(
128+
send_location_link(
115129
~id,
116130
~range=Utils.loc_to_range(loc),
117131
~target_uri=uri,

compiler/src/language_server/definition.rei renamed to compiler/src/language_server/goto.rei

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
open Grain_typed;
22

3-
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#definitionParams
3+
type goto_request_type =
4+
| Definition
5+
| TypeDefinition;
6+
47
module RequestParams: {
58
[@deriving yojson({strict: false})]
69
type t;
@@ -17,6 +20,7 @@ let process:
1720
~id: Protocol.message_id,
1821
~compiled_code: Hashtbl.t(Protocol.uri, Lsp_types.code),
1922
~documents: Hashtbl.t(Protocol.uri, string),
23+
goto_request_type,
2024
RequestParams.t
2125
) =>
2226
unit;

compiler/src/language_server/hover.re

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ open Lsp_types;
1010
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#hoverParams
1111
module RequestParams = {
1212
[@deriving yojson({strict: false})]
13-
type t = {
14-
[@key "textDocument"]
15-
text_document: Protocol.text_document_identifier,
16-
position: Protocol.position,
17-
};
13+
type t = Protocol.text_document_position_params;
1814
};
1915

2016
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#hover

compiler/src/language_server/initialize.re

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ module ResponseResult = {
7272
definition_provider: {
7373
link_support: true,
7474
},
75-
type_definition_provider: false,
75+
type_definition_provider: true,
7676
references_provider: false,
7777
document_symbol_provider: false,
7878
code_action_provider: false,

compiler/src/language_server/message.re

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type t =
1010
| TextDocumentDidChange(Protocol.uri, Code_file.DidChange.RequestParams.t)
1111
| TextDocumentInlayHint(Protocol.message_id, Inlayhint.RequestParams.t)
1212
| Formatting(Protocol.message_id, Formatting.RequestParams.t)
13-
| Definition(Protocol.message_id, Definition.RequestParams.t)
13+
| Goto(Protocol.message_id, Goto.goto_request_type, Goto.RequestParams.t)
1414
| SetTrace(Protocol.trace_value)
1515
| Unsupported
1616
| Error(string);
@@ -63,8 +63,17 @@ let of_request = (msg: Protocol.request_message): t => {
6363
| Error(msg) => Error(msg)
6464
}
6565
| {method: "textDocument/definition", id: Some(id), params: Some(params)} =>
66-
switch (Definition.RequestParams.of_yojson(params)) {
67-
| Ok(params) => Definition(id, params)
66+
switch (Goto.RequestParams.of_yojson(params)) {
67+
| Ok(params) => Goto(id, Definition, params)
68+
| Error(msg) => Error(msg)
69+
}
70+
| {
71+
method: "textDocument/typeDefinition",
72+
id: Some(id),
73+
params: Some(params),
74+
} =>
75+
switch (Goto.RequestParams.of_yojson(params)) {
76+
| Ok(params) => Goto(id, TypeDefinition, params)
6877
| Error(msg) => Error(msg)
6978
}
7079
| {method: "$/setTrace", params: Some(params)} =>

compiler/src/language_server/message.rei

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type t =
88
| TextDocumentDidChange(Protocol.uri, Code_file.DidChange.RequestParams.t)
99
| TextDocumentInlayHint(Protocol.message_id, Inlayhint.RequestParams.t)
1010
| Formatting(Protocol.message_id, Formatting.RequestParams.t)
11-
| Definition(Protocol.message_id, Definition.RequestParams.t)
11+
| Goto(Protocol.message_id, Goto.goto_request_type, Goto.RequestParams.t)
1212
| SetTrace(Protocol.trace_value)
1313
| Unsupported
1414
| Error(string);

compiler/src/language_server/protocol.re

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ type trace_value = string; // 'off' | 'messages' | 'verbose';
108108
[@deriving yojson]
109109
type text_document_identifier = {uri};
110110

111+
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams
112+
[@deriving yojson({strict: false})]
113+
type text_document_position_params = {
114+
[@key "textDocument"]
115+
text_document: text_document_identifier,
116+
position,
117+
};
118+
111119
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentSyncKind
112120
[@deriving (enum, yojson)]
113121
type text_document_sync_kind =

compiler/src/language_server/protocol.rei

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ type trace_value = string; // 'off' | 'messages' | 'verbose';
9191
[@deriving yojson]
9292
type text_document_identifier = {uri};
9393

94+
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams
95+
[@deriving yojson({strict: false})]
96+
type text_document_position_params = {
97+
[@key "textDocument"]
98+
text_document: text_document_identifier,
99+
position,
100+
};
101+
94102
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentSyncKind
95103
[@deriving (enum, yojson)]
96104
type text_document_sync_kind =

compiler/src/language_server/sourcetree.re

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -439,32 +439,15 @@ module Sourcetree: Sourcetree = {
439439
);
440440
};
441441
let enter_pattern = pat => {
442-
let rec get_type_path = pat_type => {
443-
Types.(
444-
switch (pat_type.desc) {
445-
| TTyConstr(path, _, _) => Some(path)
446-
| TTyLink(inner)
447-
| TTySubst(inner) => get_type_path(inner)
448-
| _ => None
449-
}
450-
);
451-
};
452-
let definition =
453-
switch (get_type_path(pat.pat_type)) {
454-
| Some(path) =>
455-
let decl = Env.find_type(path, pat.pat_env);
456-
if (decl.type_loc == Location.dummy_loc) {
457-
None;
458-
} else {
459-
Some(decl.type_loc);
460-
};
461-
| _ => None
462-
};
463442
segments :=
464443
[
465444
(
466445
loc_to_interval(pat.pat_loc),
467-
Pattern({pattern: pat, definition}),
446+
Pattern({
447+
pattern: pat,
448+
definition:
449+
Env.get_type_definition_loc(pat.pat_type, pat.pat_env),
450+
}),
468451
),
469452
...segments^,
470453
];

0 commit comments

Comments
 (0)