Skip to content

Commit 3134504

Browse files
authored
feat(lsp): Add or remove block braces code action (#2222)
1 parent cad45e4 commit 3134504

File tree

3 files changed

+221
-13
lines changed

3 files changed

+221
-13
lines changed

compiler/src/language_server/code_action.re

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,81 @@ let rec process_named_arg_label = (uri, results: list(Sourcetree.node)) => {
111111
};
112112
};
113113

114+
let rec process_add_or_remove_braces = (uri, results: list(Sourcetree.node)) => {
115+
Typedtree.(
116+
switch (results) {
117+
| [Value({exp: {exp_desc: TExpLambda([mb], _)}}), ...rest] =>
118+
switch (mb.mb_body.exp_desc) {
119+
| TExpBlock([lone_block_expr]) =>
120+
let before_expr_range =
121+
Utils.loc_to_range({
122+
...mb.mb_body.exp_loc,
123+
loc_end: lone_block_expr.exp_loc.loc_start,
124+
});
125+
let after_expr_range =
126+
Utils.loc_to_range({
127+
...mb.mb_body.exp_loc,
128+
loc_start: lone_block_expr.exp_loc.loc_end,
129+
});
130+
Some(
131+
ResponseResult.{
132+
title: "Remove block braces",
133+
kind: "remove-block-braces",
134+
edit: {
135+
document_changes: [
136+
{
137+
text_document: {
138+
uri,
139+
version: None,
140+
},
141+
edits: [
142+
{range: before_expr_range, new_text: ""},
143+
{range: after_expr_range, new_text: ""},
144+
],
145+
},
146+
],
147+
},
148+
},
149+
);
150+
| TExpBlock(_) => process_add_or_remove_braces(uri, rest)
151+
| _ =>
152+
let before_expr_range =
153+
Utils.loc_to_range({
154+
...mb.mb_body.exp_loc,
155+
loc_end: mb.mb_body.exp_loc.loc_start,
156+
});
157+
let after_expr_range =
158+
Utils.loc_to_range({
159+
...mb.mb_body.exp_loc,
160+
loc_start: mb.mb_body.exp_loc.loc_end,
161+
});
162+
Some(
163+
ResponseResult.{
164+
title: "Add block braces",
165+
kind: "add-block-braces",
166+
edit: {
167+
document_changes: [
168+
{
169+
text_document: {
170+
uri,
171+
version: None,
172+
},
173+
edits: [
174+
{range: before_expr_range, new_text: "{ "},
175+
{range: after_expr_range, new_text: " }"},
176+
],
177+
},
178+
],
179+
},
180+
},
181+
);
182+
}
183+
| [_, ...rest] => process_add_or_remove_braces(uri, rest)
184+
| _ => None
185+
}
186+
);
187+
};
188+
114189
let process =
115190
(
116191
~id: Protocol.message_id,
@@ -129,6 +204,7 @@ let process =
129204
[
130205
process_explicit_type_annotation(params.text_document.uri, results),
131206
process_named_arg_label(params.text_document.uri, results),
207+
process_add_or_remove_braces(params.text_document.uri, results),
132208
],
133209
);
134210

compiler/src/language_server/sourcetree.re

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ module type Sourcetree = {
140140
| Value({
141141
env: Env.t,
142142
value_type: Types.type_expr,
143+
exp: Typedtree.expression,
143144
loc: Location.t,
144145
definition: option(Location.t),
145146
})
@@ -234,6 +235,7 @@ module Sourcetree: Sourcetree = {
234235
| Value({
235236
env: Env.t,
236237
value_type: Types.type_expr,
238+
exp: Typedtree.expression,
237239
loc: Location.t,
238240
definition: option(Location.t),
239241
})
@@ -323,6 +325,7 @@ module Sourcetree: Sourcetree = {
323325
Value({
324326
env: exp.exp_env,
325327
value_type: desc.val_type,
328+
exp,
326329
loc: exp.exp_loc,
327330
definition: Some(desc.val_loc),
328331
}),
@@ -337,6 +340,7 @@ module Sourcetree: Sourcetree = {
337340
Value({
338341
env: exp.exp_env,
339342
value_type: desc.val_type,
343+
exp,
340344
loc: exp.exp_loc,
341345
definition: Some(desc.val_loc),
342346
}),
@@ -363,6 +367,7 @@ module Sourcetree: Sourcetree = {
363367
Value({
364368
env: exp.exp_env,
365369
value_type: exp.exp_type,
370+
exp,
366371
loc: exp.exp_loc,
367372
definition: None,
368373
}),
@@ -396,6 +401,7 @@ module Sourcetree: Sourcetree = {
396401
Value({
397402
env: exp.exp_env,
398403
value_type: value.val_type,
404+
exp,
399405
loc,
400406
definition: Some(value.val_loc),
401407
}),
@@ -424,6 +430,7 @@ module Sourcetree: Sourcetree = {
424430
Value({
425431
env: exp.exp_env,
426432
value_type: desc.cstr_res,
433+
exp,
427434
loc: exp.exp_loc,
428435
definition: Some(desc.cstr_loc),
429436
}),
@@ -453,6 +460,7 @@ module Sourcetree: Sourcetree = {
453460
Value({
454461
env: exp.exp_env,
455462
value_type: exp.exp_type,
463+
exp,
456464
loc: exp.exp_loc,
457465
definition: None,
458466
}),

compiler/test/suites/grainlsp.re

Lines changed: 137 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ let lsp_range = (start_position, end_position) => {
2525
]);
2626
};
2727

28-
let lsp_text_document_edit = (uri, range, new_text) => {
28+
let lsp_text_document_edit = (uri, edits) => {
2929
`Assoc([
3030
(
3131
"documentChanges",
@@ -37,9 +37,16 @@ let lsp_text_document_edit = (uri, range, new_text) => {
3737
),
3838
(
3939
"edits",
40-
`List([
41-
`Assoc([("range", range), ("newText", `String(new_text))]),
42-
]),
40+
`List(
41+
List.map(
42+
((range, new_text)) =>
43+
`Assoc([
44+
("range", range),
45+
("newText", `String(new_text)),
46+
]),
47+
edits,
48+
),
49+
),
4350
),
4451
]),
4552
]),
@@ -208,8 +215,7 @@ let abc = { x: 1 }
208215
"edit",
209216
lsp_text_document_edit(
210217
"file:///a.gr",
211-
lsp_range((2, 7), (2, 7)),
212-
": T",
218+
[(lsp_range((2, 7), (2, 7)), ": T")],
213219
),
214220
),
215221
]),
@@ -221,7 +227,10 @@ let abc = { x: 1 }
221227
"file:///a.gr",
222228
{|module A
223229
record T { x: Number }
224-
let f = val => val.x
230+
let f = val => {
231+
print(val)
232+
val.x
233+
}
225234
|},
226235
lsp_input(
227236
"textDocument/codeAction",
@@ -239,8 +248,7 @@ let f = val => val.x
239248
"edit",
240249
lsp_text_document_edit(
241250
"file:///a.gr",
242-
lsp_range((2, 11), (2, 11)),
243-
": T",
251+
[(lsp_range((2, 11), (2, 11)), ": T")],
244252
),
245253
),
246254
]),
@@ -288,8 +296,7 @@ f("y", x="x", "z")
288296
"edit",
289297
lsp_text_document_edit(
290298
"file:///a.gr",
291-
lsp_range((2, 2), (2, 2)),
292-
"y=",
299+
[(lsp_range((2, 2), (2, 2)), "y=")],
293300
),
294301
),
295302
]),
@@ -319,8 +326,7 @@ f("y", x="x", "z")
319326
"edit",
320327
lsp_text_document_edit(
321328
"file:///a.gr",
322-
lsp_range((2, 14), (2, 14)),
323-
"z=",
329+
[(lsp_range((2, 14), (2, 14)), "z=")],
324330
),
325331
),
326332
]),
@@ -345,6 +351,124 @@ f(x="x")
345351
`Null,
346352
);
347353

354+
assertLspOutput(
355+
"code_action_remove_function_block_braces_1",
356+
"file:///a.gr",
357+
{|module A
358+
let f = (x) => {
359+
x
360+
}
361+
|},
362+
lsp_input(
363+
"textDocument/codeAction",
364+
`Assoc([
365+
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
366+
("range", lsp_range((2, 2), (2, 3))),
367+
("context", `Assoc([("diagnostics", `List([]))])),
368+
]),
369+
),
370+
`List([
371+
`Assoc([
372+
("title", `String("Remove block braces")),
373+
("kind", `String("remove-block-braces")),
374+
(
375+
"edit",
376+
lsp_text_document_edit(
377+
"file:///a.gr",
378+
[
379+
(lsp_range((1, 15), (2, 2)), ""),
380+
(lsp_range((2, 3), (3, 1)), ""),
381+
],
382+
),
383+
),
384+
]),
385+
]),
386+
);
387+
388+
assertLspOutput(
389+
"code_action_remove_function_block_braces_2",
390+
"file:///a.gr",
391+
{|module A
392+
let f = (x) => {
393+
print(x)
394+
x
395+
}
396+
|},
397+
lsp_input(
398+
"textDocument/codeAction",
399+
`Assoc([
400+
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
401+
("range", lsp_range((2, 2), (2, 3))),
402+
("context", `Assoc([("diagnostics", `List([]))])),
403+
]),
404+
),
405+
`Null,
406+
);
407+
408+
assertLspOutput(
409+
"code_action_add_function_block_braces_1",
410+
"file:///a.gr",
411+
{|module A
412+
let f = (x) => print(x)
413+
|},
414+
lsp_input(
415+
"textDocument/codeAction",
416+
`Assoc([
417+
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
418+
("range", lsp_range((1, 15), (1, 16))),
419+
("context", `Assoc([("diagnostics", `List([]))])),
420+
]),
421+
),
422+
`List([
423+
`Assoc([
424+
("title", `String("Add block braces")),
425+
("kind", `String("add-block-braces")),
426+
(
427+
"edit",
428+
lsp_text_document_edit(
429+
"file:///a.gr",
430+
[
431+
(lsp_range((1, 15), (1, 15)), "{ "),
432+
(lsp_range((1, 23), (1, 23)), " }"),
433+
],
434+
),
435+
),
436+
]),
437+
]),
438+
);
439+
440+
assertLspOutput(
441+
"code_action_add_function_block_braces_2",
442+
"file:///a.gr",
443+
{|module A
444+
let f = () => () => print(1)
445+
|},
446+
lsp_input(
447+
"textDocument/codeAction",
448+
`Assoc([
449+
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
450+
("range", lsp_range((1, 20), (1, 21))),
451+
("context", `Assoc([("diagnostics", `List([]))])),
452+
]),
453+
),
454+
`List([
455+
`Assoc([
456+
("title", `String("Add block braces")),
457+
("kind", `String("add-block-braces")),
458+
(
459+
"edit",
460+
lsp_text_document_edit(
461+
"file:///a.gr",
462+
[
463+
(lsp_range((1, 20), (1, 20)), "{ "),
464+
(lsp_range((1, 28), (1, 28)), " }"),
465+
],
466+
),
467+
),
468+
]),
469+
]),
470+
);
471+
348472
assertLspOutput(
349473
"hover_pattern",
350474
"file:///a.gr",

0 commit comments

Comments
 (0)