Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: emit code actions from the compiler that the editor tooling can use #7040

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions jscomp/bsc/rescript_compiler_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ let buckle_script_flags : (string * Bsc_args.spec * string) array =
"-bs-ast", unit_call(fun _ -> Js_config.binary_ast := true; Js_config.syntax_only := true),
"*internal* Generate binary .mli_ast and ml_ast and stop";

"-code-action-data", unit_call(fun _ -> Js_config.code_action_data := true),
"*internal* Emit code action data";

Comment on lines +276 to +278
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't actually used yet, but we can probably have a bsc config like this.

"-bs-syntax-only", set Js_config.syntax_only,
"*internal* Only check syntax";

Expand Down
1 change: 1 addition & 0 deletions jscomp/common/js_config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ let all_module_aliases = ref false
let no_stdlib = ref false
let no_export = ref false
let as_ppx = ref false
let code_action_data = ref false

let int_of_jsx_version = function
| Jsx_v3 -> 3
Expand Down
2 changes: 2 additions & 0 deletions jscomp/common/js_config.mli
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,5 @@ val as_pp : bool ref
val self_stack : string Stack.t

val modules : bool ref

val code_action_data : bool ref
61 changes: 61 additions & 0 deletions jscomp/ml/code_action_data.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
type code_action_type = WrapWith of {left: string; right: string}
type code_action_style = Regular | QuickFix
type code_action = {
style: code_action_style;
type_: code_action_type;
title: string;
}

let code_action_data = ref []
let add_code_action (data : code_action) =
code_action_data := data :: !code_action_data
let get_code_action_data () = !code_action_data

let escape text =
let ln = String.length text in
let buf = Buffer.create ln in
let rec loop i =
if i < ln then (
(match text.[i] with
| '\012' -> Buffer.add_string buf "\\f"
| '\\' -> Buffer.add_string buf "\\\\"
| '"' -> Buffer.add_string buf "\\\""
| '\n' -> Buffer.add_string buf "\\n"
| '\b' -> Buffer.add_string buf "\\b"
| '\r' -> Buffer.add_string buf "\\r"
| '\t' -> Buffer.add_string buf "\\t"
| c -> Buffer.add_char buf c);
loop (i + 1))
in
loop 0;
Buffer.contents buf

let loc_to_json loc =
Printf.sprintf
"{\"start\": {\"line\": %s, \"col\": %s},\"end\": {\"line\": %s, \"col\": \
%s}}"
(loc.Location.loc_start.pos_lnum |> string_of_int)
(loc.loc_start.pos_cnum |> string_of_int)
(loc.loc_end.pos_lnum |> string_of_int)
(loc.loc_end.pos_cnum |> string_of_int)

let code_action_type_to_json = function
| WrapWith {left; right} ->
Printf.sprintf "\"type\": \"wrapWith\", \"wrapLeft\": \"%s\", \"wrapRight\": \"%s\""
(escape left) (escape right)

let emit_code_actions_data loc ppf =
match !code_action_data with
| [] -> ()
| code_actions ->
Format.fprintf ppf "@\n=== CODE ACTIONS ===@\n";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build system and editor tooling can extract this line + the rest of the content whenever it encounters it, and extract the code actions from there. And show the actual error in the terminal and in the editor without this text.

code_actions
|> List.iter (fun data ->
Format.fprintf ppf
"{\"title\": \"%s\", \"kind\": \"%s\" \"loc\": %s, %s}"
(escape data.title)
(match data.style with
| Regular -> "regular"
| QuickFix -> "quickfix")
(loc_to_json loc)
(code_action_type_to_json data.type_))
12 changes: 12 additions & 0 deletions jscomp/ml/code_action_data.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type code_action_type = WrapWith of {left: string; right: string}
type code_action_style = Regular | QuickFix
type code_action = {
style: code_action_style;
type_: code_action_type;
title: string;
}

val add_code_action: code_action -> unit
val get_code_action_data: unit -> code_action list

val emit_code_actions_data: Location.t -> Format.formatter -> unit
14 changes: 11 additions & 3 deletions jscomp/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,14 @@ let simple_conversions = [
let print_simple_conversion ppf (actual, expected) =
try (
let converter = List.assoc (actual, expected) simple_conversions in
Code_action_data.add_code_action {
Code_action_data.style = QuickFix;
type_ = WrapWith {
left = converter ^ "(";
right = ")"
};
title = Printf.sprintf "Convert %s to %s" actual expected
};
fprintf ppf "@,@,@[<v 2>You can convert @{<info>%s@} to @{<info>%s@} with @{<info>%s@}.@]" actual expected converter
) with | Not_found -> ()

Expand Down Expand Up @@ -4045,14 +4053,14 @@ let report_error env ppf = function
let super_report_error_no_wrap_printing_env = report_error


let report_error env ppf err =
Printtyp.wrap_printing_env env (fun () -> report_error env ppf err)
let report_error loc env ppf err =
Printtyp.wrap_printing_env env (fun () -> report_error env ppf err; Code_action_data.emit_code_actions_data loc ppf;)

let () =
Location.register_error_of_exn
(function
| Error (loc, env, err) ->
Some (Location.error_of_printer loc (report_error env) err)
Some (Location.error_of_printer loc (report_error loc env) err)
| Error_forward err ->
Some err
| _ ->
Expand Down
2 changes: 1 addition & 1 deletion jscomp/ml/typecore.mli
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ exception Error_forward of Location.error
val super_report_error_no_wrap_printing_env: Env.t -> formatter -> error -> unit


val report_error: Env.t -> formatter -> error -> unit
val report_error: Location.t -> Env.t -> formatter -> error -> unit
(* Deprecated. Use Location.{error_of_exn, report_error}. *)

(* Forward declaration, to be filled in by Typemod.type_module *)
Expand Down
Loading