Skip to content

Commit

Permalink
feat(lsp): Add or remove block braces code action (#2222)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-snezhko authored Jan 2, 2025
1 parent cad45e4 commit 3134504
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 13 deletions.
76 changes: 76 additions & 0 deletions compiler/src/language_server/code_action.re
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,81 @@ let rec process_named_arg_label = (uri, results: list(Sourcetree.node)) => {
};
};

let rec process_add_or_remove_braces = (uri, results: list(Sourcetree.node)) => {
Typedtree.(
switch (results) {
| [Value({exp: {exp_desc: TExpLambda([mb], _)}}), ...rest] =>
switch (mb.mb_body.exp_desc) {
| TExpBlock([lone_block_expr]) =>
let before_expr_range =
Utils.loc_to_range({
...mb.mb_body.exp_loc,
loc_end: lone_block_expr.exp_loc.loc_start,
});
let after_expr_range =
Utils.loc_to_range({
...mb.mb_body.exp_loc,
loc_start: lone_block_expr.exp_loc.loc_end,
});
Some(
ResponseResult.{
title: "Remove block braces",
kind: "remove-block-braces",
edit: {
document_changes: [
{
text_document: {
uri,
version: None,
},
edits: [
{range: before_expr_range, new_text: ""},
{range: after_expr_range, new_text: ""},
],
},
],
},
},
);
| TExpBlock(_) => process_add_or_remove_braces(uri, rest)
| _ =>
let before_expr_range =
Utils.loc_to_range({
...mb.mb_body.exp_loc,
loc_end: mb.mb_body.exp_loc.loc_start,
});
let after_expr_range =
Utils.loc_to_range({
...mb.mb_body.exp_loc,
loc_start: mb.mb_body.exp_loc.loc_end,
});
Some(
ResponseResult.{
title: "Add block braces",
kind: "add-block-braces",
edit: {
document_changes: [
{
text_document: {
uri,
version: None,
},
edits: [
{range: before_expr_range, new_text: "{ "},
{range: after_expr_range, new_text: " }"},
],
},
],
},
},
);
}
| [_, ...rest] => process_add_or_remove_braces(uri, rest)
| _ => None
}
);
};

let process =
(
~id: Protocol.message_id,
Expand All @@ -129,6 +204,7 @@ let process =
[
process_explicit_type_annotation(params.text_document.uri, results),
process_named_arg_label(params.text_document.uri, results),
process_add_or_remove_braces(params.text_document.uri, results),
],
);

Expand Down
8 changes: 8 additions & 0 deletions compiler/src/language_server/sourcetree.re
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ module type Sourcetree = {
| Value({
env: Env.t,
value_type: Types.type_expr,
exp: Typedtree.expression,
loc: Location.t,
definition: option(Location.t),
})
Expand Down Expand Up @@ -234,6 +235,7 @@ module Sourcetree: Sourcetree = {
| Value({
env: Env.t,
value_type: Types.type_expr,
exp: Typedtree.expression,
loc: Location.t,
definition: option(Location.t),
})
Expand Down Expand Up @@ -323,6 +325,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: desc.val_type,
exp,
loc: exp.exp_loc,
definition: Some(desc.val_loc),
}),
Expand All @@ -337,6 +340,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: desc.val_type,
exp,
loc: exp.exp_loc,
definition: Some(desc.val_loc),
}),
Expand All @@ -363,6 +367,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: exp.exp_type,
exp,
loc: exp.exp_loc,
definition: None,
}),
Expand Down Expand Up @@ -396,6 +401,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: value.val_type,
exp,
loc,
definition: Some(value.val_loc),
}),
Expand Down Expand Up @@ -424,6 +430,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: desc.cstr_res,
exp,
loc: exp.exp_loc,
definition: Some(desc.cstr_loc),
}),
Expand Down Expand Up @@ -453,6 +460,7 @@ module Sourcetree: Sourcetree = {
Value({
env: exp.exp_env,
value_type: exp.exp_type,
exp,
loc: exp.exp_loc,
definition: None,
}),
Expand Down
150 changes: 137 additions & 13 deletions compiler/test/suites/grainlsp.re
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let lsp_range = (start_position, end_position) => {
]);
};

let lsp_text_document_edit = (uri, range, new_text) => {
let lsp_text_document_edit = (uri, edits) => {
`Assoc([
(
"documentChanges",
Expand All @@ -37,9 +37,16 @@ let lsp_text_document_edit = (uri, range, new_text) => {
),
(
"edits",
`List([
`Assoc([("range", range), ("newText", `String(new_text))]),
]),
`List(
List.map(
((range, new_text)) =>
`Assoc([
("range", range),
("newText", `String(new_text)),
]),
edits,
),
),
),
]),
]),
Expand Down Expand Up @@ -208,8 +215,7 @@ let abc = { x: 1 }
"edit",
lsp_text_document_edit(
"file:///a.gr",
lsp_range((2, 7), (2, 7)),
": T",
[(lsp_range((2, 7), (2, 7)), ": T")],
),
),
]),
Expand All @@ -221,7 +227,10 @@ let abc = { x: 1 }
"file:///a.gr",
{|module A
record T { x: Number }
let f = val => val.x
let f = val => {
print(val)
val.x
}
|},
lsp_input(
"textDocument/codeAction",
Expand All @@ -239,8 +248,7 @@ let f = val => val.x
"edit",
lsp_text_document_edit(
"file:///a.gr",
lsp_range((2, 11), (2, 11)),
": T",
[(lsp_range((2, 11), (2, 11)), ": T")],
),
),
]),
Expand Down Expand Up @@ -288,8 +296,7 @@ f("y", x="x", "z")
"edit",
lsp_text_document_edit(
"file:///a.gr",
lsp_range((2, 2), (2, 2)),
"y=",
[(lsp_range((2, 2), (2, 2)), "y=")],
),
),
]),
Expand Down Expand Up @@ -319,8 +326,7 @@ f("y", x="x", "z")
"edit",
lsp_text_document_edit(
"file:///a.gr",
lsp_range((2, 14), (2, 14)),
"z=",
[(lsp_range((2, 14), (2, 14)), "z=")],
),
),
]),
Expand All @@ -345,6 +351,124 @@ f(x="x")
`Null,
);

assertLspOutput(
"code_action_remove_function_block_braces_1",
"file:///a.gr",
{|module A
let f = (x) => {
x
}
|},
lsp_input(
"textDocument/codeAction",
`Assoc([
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
("range", lsp_range((2, 2), (2, 3))),
("context", `Assoc([("diagnostics", `List([]))])),
]),
),
`List([
`Assoc([
("title", `String("Remove block braces")),
("kind", `String("remove-block-braces")),
(
"edit",
lsp_text_document_edit(
"file:///a.gr",
[
(lsp_range((1, 15), (2, 2)), ""),
(lsp_range((2, 3), (3, 1)), ""),
],
),
),
]),
]),
);

assertLspOutput(
"code_action_remove_function_block_braces_2",
"file:///a.gr",
{|module A
let f = (x) => {
print(x)
x
}
|},
lsp_input(
"textDocument/codeAction",
`Assoc([
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
("range", lsp_range((2, 2), (2, 3))),
("context", `Assoc([("diagnostics", `List([]))])),
]),
),
`Null,
);

assertLspOutput(
"code_action_add_function_block_braces_1",
"file:///a.gr",
{|module A
let f = (x) => print(x)
|},
lsp_input(
"textDocument/codeAction",
`Assoc([
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
("range", lsp_range((1, 15), (1, 16))),
("context", `Assoc([("diagnostics", `List([]))])),
]),
),
`List([
`Assoc([
("title", `String("Add block braces")),
("kind", `String("add-block-braces")),
(
"edit",
lsp_text_document_edit(
"file:///a.gr",
[
(lsp_range((1, 15), (1, 15)), "{ "),
(lsp_range((1, 23), (1, 23)), " }"),
],
),
),
]),
]),
);

assertLspOutput(
"code_action_add_function_block_braces_2",
"file:///a.gr",
{|module A
let f = () => () => print(1)
|},
lsp_input(
"textDocument/codeAction",
`Assoc([
("textDocument", `Assoc([("uri", `String("file:///a.gr"))])),
("range", lsp_range((1, 20), (1, 21))),
("context", `Assoc([("diagnostics", `List([]))])),
]),
),
`List([
`Assoc([
("title", `String("Add block braces")),
("kind", `String("add-block-braces")),
(
"edit",
lsp_text_document_edit(
"file:///a.gr",
[
(lsp_range((1, 20), (1, 20)), "{ "),
(lsp_range((1, 28), (1, 28)), " }"),
],
),
),
]),
]),
);

assertLspOutput(
"hover_pattern",
"file:///a.gr",
Expand Down

0 comments on commit 3134504

Please sign in to comment.