Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions compiler/src/diagnostics/comments.re
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ module type OrderedComments = {
};

module MakeOrderedComments =
(Raw: {
let comments: list(Typedtree.comment);
})
(
Raw: {
let comments: list(Typedtree.comment);
let extract_attributes: bool;
},
)
: OrderedComments => {
module IntMap = Map.Make(Int);

Expand Down Expand Up @@ -117,9 +120,15 @@ module MakeOrderedComments =
let data = (comment, None, []);
(cmt_loc.loc_start.pos_lnum, cmt_loc.loc_end.pos_lnum, data);
| Doc({cmt_source, cmt_content, cmt_loc}) =>
let (description, attributes) =
Attribute.extract(cmt_source, cmt_content, cmt_loc);
let data = (comment, description, attributes);
let data =
if (Raw.extract_attributes) {
let (description, attributes) =
Attribute.extract(cmt_source, cmt_content, cmt_loc);
(comment, description, attributes);
} else {
(comment, None, []);
};

(cmt_loc.loc_start.pos_lnum, cmt_loc.loc_end.pos_lnum, data);
};
comments.by_start_lnum =
Expand All @@ -137,10 +146,12 @@ module MakeOrderedComments =
let iter = fn => IntMap.iter(fn, comments.by_start_lnum);
};

let to_ordered = (comments): (module OrderedComments) =>
let to_ordered =
(~extract_attributes=true, comments): (module OrderedComments) =>
(module
MakeOrderedComments({
let comments = comments;
let extract_attributes = extract_attributes;
}));

let start_line = (comment: Typedtree.comment) => {
Expand Down
112 changes: 112 additions & 0 deletions compiler/src/language_server/code_action.re
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,29 @@ let named_arg_label = (range, uri, arg_label) => {
};
};

let add_graindoc = (range, uri, message) => {
ResponseResult.{
title: "Add Graindoc",
kind: "add-graindoc",
edit: {
document_changes: [
{
text_document: {
uri,
version: None,
},
edits: [
{
range,
new_text: message,
},
],
},
],
},
};
};

let send_code_actions =
(id: Protocol.message_id, code_actions: list(ResponseResult.code_action)) => {
Protocol.response(~id, ResponseResult.to_yojson(Some(code_actions)));
Expand Down Expand Up @@ -214,6 +237,90 @@ let rec process_add_or_remove_braces = (uri, results: list(Sourcetree.node)) =>
);
};

let get_end_of_last_line = (loc: Location.t) => {
{
...loc,
loc_start: {
...loc.loc_start,
pos_cnum: Int.max_int,
pos_lnum: loc.loc_start.pos_lnum - 1,
},
loc_end: {
...loc.loc_start,
pos_cnum: Int.max_int,
pos_lnum: loc.loc_start.pos_lnum - 1,
},
};
};
let template_graindoc = fn => {
let output = Buffer.create(128);
Buffer.add_string(output, "\n/**\n");
Buffer.add_string(output, " *\n"); // Blank spot for description entry
Buffer.add_string(output, " *\n"); // Spacing
fn(output);
Buffer.add_string(output, " * @example\n");
Buffer.add_string(output, " *\n"); // Spacing
Buffer.add_string(output, " * @since\n");
Buffer.add_string(output, " */");
Buffer.contents(output);
};
let rec process_graindoc =
(
uri,
results: list(Sourcetree.node),
comments: list(Typedtree.comment),
) => {
switch (results) {
| [LetBind({pat, expr, loc}), ..._] =>
let ordered = Comments.to_ordered(~extract_attributes=false, comments);
let comment =
Comments.Doc.ending_on(~lnum=loc.loc_start.pos_lnum - 1, ordered);
switch (comment) {
| Some((Doc(_), _, _)) => None
| _ =>
let loc = get_end_of_last_line(loc);
let message =
template_graindoc(output => {
switch (expr.exp_type.desc) {
| TTyArrow(args, ret_typ, _) =>
Buffer.add_string(output, " *\n"); // Spacing
List.iteri(
(index, (label, _)) => {
let param_name =
switch (label) {
| Types.Labeled({txt})
| Default({txt}) => txt
| Unlabeled => string_of_int(index)
};
Buffer.add_string(
output,
Printf.sprintf(" * @param %s:\n", param_name),
);
},
args,
);
Buffer.add_string(output, " * @returns \n");
| _ => ()
}
});
Some(add_graindoc(Utils.loc_to_range(loc), uri, message));
};
| [Module({loc}), ...rest] =>
let ordered = Comments.to_ordered(~extract_attributes=false, comments);
let comment =
Comments.Doc.ending_on(~lnum=loc.loc_start.pos_lnum - 1, ordered);
switch (comment) {
| Some((Doc(_), _, _)) => None
| _ =>
let loc = get_end_of_last_line(loc);
let message = template_graindoc(_ => ());
Some(add_graindoc(Utils.loc_to_range(loc), uri, message));
};
| [_, ...rest] => process_graindoc(uri, rest, comments)
| _ => None
};
};

let process =
(
~id: Protocol.message_id,
Expand All @@ -233,6 +340,11 @@ 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),
process_graindoc(
params.text_document.uri,
results,
program.comments,
),
],
);

Expand Down
35 changes: 35 additions & 0 deletions compiler/src/language_server/sourcetree.re
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ module type Sourcetree = {
| Include({
path: Path.t,
loc: Location.t,
})
| LetBind({
rec_flag: Typedtree.rec_flag,
mut_flag: Typedtree.mut_flag,
pat: Typedtree.pattern,
expr: Typedtree.expression,
loc: Location.t,
});

type sourcetree = t(node);
Expand Down Expand Up @@ -276,6 +283,13 @@ module Sourcetree: Sourcetree = {
| Include({
path: Path.t,
loc: Location.t,
})
| LetBind({
rec_flag: Typedtree.rec_flag,
mut_flag: Typedtree.mut_flag,
pat: Typedtree.pattern,
expr: Typedtree.expression,
loc: Location.t,
});

type sourcetree = t(node);
Expand Down Expand Up @@ -561,6 +575,27 @@ module Sourcetree: Sourcetree = {
),
...segments^,
]
| TTopLet(rec_flag, mut_flag, binds) =>
segments :=
List.fold_left(
(segments, {vb_pat, vb_expr, vb_loc}) => {
[
(
loc_to_interval(vb_loc),
LetBind({
rec_flag,
mut_flag,
pat: vb_pat,
expr: vb_expr,
loc: vb_loc,
}),
),
...segments,
]
},
segments^,
binds,
)
| _ => ()
};
};
Expand Down
Loading