Skip to content

Commit

Permalink
[flow][try] Signature help
Browse files Browse the repository at this point in the history
Summary: Changelog: [website] We now provide signature help service in try-flow

Reviewed By: panagosg7

Differential Revision: D55652340

fbshipit-source-id: f7e51ff8953abdb1c266729b8cce43a1c4155ddf
  • Loading branch information
SamChou19815 authored and facebook-github-bot committed Apr 2, 2024
1 parent 45043cd commit fd06398
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
94 changes: 94 additions & 0 deletions src/flow_dot_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,40 @@ let infer_type filename content line col js_config_object : Loc.t * (string, str
(loc, Ok (Ty_printer.string_of_type_at_pos_result ~exact_by_default:true result))
end

let signature_help filename content line col js_config_object :
((ServerProt.Response.func_details_result list * int) option, string) result =
let filename = File_key.SourceFile filename in
let root = File_path.dummy_path in
match parse_content filename content with
| Error _ -> Error "parse error"
| Ok (ast, file_sig) ->
let (_, docblock) =
Docblock_parser.(
parse_docblock
~max_tokens:docblock_max_tokens
~file_options:Files.default_options
filename
content
)
in
let (cx, typed_ast) = infer_and_merge ~root filename js_config_object docblock ast file_sig in
let cursor_loc = mk_loc filename line col in
let func_details =
Signature_help.find_signatures
~loc_of_aloc
~get_ast_from_shared_mem:(fun _ -> None)
~cx
~file_sig
~ast
~typed_ast
cursor_loc
in
begin
match func_details with
| Ok details -> Ok details
| Error _ -> Error "Failed to normalize type"
end

let types_to_json types ~strip_root =
Hh_json.(
Reason.(
Expand Down Expand Up @@ -607,6 +641,46 @@ let completion_item_to_json
in
JSON_Object props

let signature_to_json { ServerProt.Response.func_documentation; param_tys; return_ty } =
let open Hh_json in
let open Utils_js in
let documentation_props = function
| None -> []
| Some doc -> [("documentation", JSON_Object [("value", JSON_String doc)])]
in
let props = documentation_props func_documentation in
let props =
( "parameters",
JSON_Array
(Base.List.map
param_tys
~f:(fun { ServerProt.Response.param_documentation; param_name; param_ty } ->
JSON_Object
(("label", JSON_String (spf "%s: %s" param_name param_ty))
:: documentation_props param_documentation
)
)
)
)
:: props
in
let props =
let sig_str =
Utils_js.spf
"(%s): %s"
(Base.List.map
param_tys
~f:(fun { ServerProt.Response.param_documentation = _; param_name; param_ty } ->
spf "%s: %s" param_name param_ty
)
|> Base.String.concat ~sep:", "
)
return_ty
in
("label", JSON_String sig_str) :: props
in
JSON_Object props

let autocomplete js_file js_content js_line js_col js_config_object =
let filename = Js.to_string js_file in
let content = Js.to_string js_content in
Expand Down Expand Up @@ -634,6 +708,24 @@ let get_def js_file js_content js_line js_col js_config_object =
|> js_of_json
| Error msg -> failwith msg

let signature_help js_file js_content js_line js_col js_config_object =
let filename = Js.to_string js_file in
let content = Js.to_string js_content in
let line = Js.parseInt js_line in
let col = Js.parseInt js_col in
match signature_help filename content line col js_config_object with
| Error msg -> failwith msg
| Ok None -> Js.Unsafe.inject Js.null
| Ok (Some (signatures, n)) ->
let open Hh_json in
JSON_Object
[
("signatures", JSON_Array (Base.List.map signatures ~f:signature_to_json));
("activeParameter", JSON_Number (string_of_int n));
("activeSignature", JSON_Number "0");
]
|> js_of_json

let type_at_pos js_file js_content js_line js_col js_config_object =
let filename = Js.to_string js_file in
let content = Js.to_string js_content in
Expand Down Expand Up @@ -790,4 +882,6 @@ let () = Js.Unsafe.set exports "autocomplete" (Js.wrap_callback autocomplete)

let () = Js.Unsafe.set exports "getDef" (Js.wrap_callback get_def)

let () = Js.Unsafe.set exports "signatureHelp" (Js.wrap_callback signature_help)

let () = Js.Unsafe.set exports "typeAtPos" (Js.wrap_callback type_at_pos)
7 changes: 7 additions & 0 deletions website/libs/flow_js.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,12 @@ declare type FlowJs = {
col: number,
options: {[string]: mixed},
): string,
signatureHelp(
filename: string,
body: string,
line: number,
col: number,
options: {[string]: mixed},
): any,
parse(body: string, options: FlowJsParseOptions): interface {},
};
2 changes: 2 additions & 0 deletions website/src/try-flow/TryFlow.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
setAutoCompleteFunction,
setGetDefFunction,
setTypeAtPosFunction,
setSignatureHelpFunction,
} from './configured-monaco';
import FlowJsServices from './flow-services';
import createTokensProvider from './tokens-theme-provider';
Expand Down Expand Up @@ -159,6 +160,7 @@ export default component TryFlow(
setAutoCompleteFunction(flowService);
setGetDefFunction(flowService);
setTypeAtPosFunction(flowService);
setSignatureHelpFunction(flowService);

const model = monaco.editor.getModels()[0];
if (model == null || flowService == null) return;
Expand Down
27 changes: 27 additions & 0 deletions website/src/try-flow/configured-monaco.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ function setTypeAtPosFunction(flowService: ?FlowJsServices): void {
);
}

let signatureHelpFunctionForMonaco = (value: string, position: Position): any =>
null;

function setSignatureHelpFunction(flowService: ?FlowJsServices): void {
signatureHelpFunctionForMonaco = (value, position) =>
flowService?.signatureHelp(
'-',
value,
position.lineNumber,
position.column - 1,
);
}

monaco.languages.register({
id: 'flow',
extensions: ['.js', '.flow'],
Expand Down Expand Up @@ -180,11 +193,25 @@ monaco.languages.registerHoverProvider('flow', {
};
},
});
monaco.languages.registerSignatureHelpProvider('flow', {
signatureHelpTriggerCharacters: ['(', ','],
provideSignatureHelp(model, position) {
try {
const result = signatureHelpFunctionForMonaco(model.getValue(), position);
if (result == null) return null;
return {value: result, dispose() {}};
} catch (e) {
console.error(e);
return null;
}
},
});
loader.config({monaco});

export {
monaco,
setAutoCompleteFunction,
setGetDefFunction,
setTypeAtPosFunction,
setSignatureHelpFunction,
};
9 changes: 9 additions & 0 deletions website/src/try-flow/flow-services.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ export default class FlowJsServices {
return this._flow.typeAtPos(filename, body, line, col, this.config);
}

signatureHelp(
filename: string,
body: string,
line: number,
col: number,
): any {
return this._flow.signatureHelp(filename, body, line, col, this.config);
}

parseAstToJsonString(body: string): interface {} {
return this._flow.parse(body, PARSE_OPTIONS);
}
Expand Down

0 comments on commit fd06398

Please sign in to comment.