Skip to content

Universal dot completion #1054

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

Merged
merged 34 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
565edda
wip complete pipeable functions from dot completion on record when re…
zth Nov 5, 2024
4347fa3
correctly insert completion item text removing the dot when selecting…
zth Nov 6, 2024
eefe5f6
add experimental mainTypeForModule annotation
zth Nov 6, 2024
ca1c8d1
complete modules in payload of mainTypeForModule
zth Nov 7, 2024
7110db8
rename attribute
zth Nov 12, 2024
af54200
hover for new decorator
zth Nov 12, 2024
e3d1470
allow extra module completions also for pipe
zth Nov 13, 2024
72a522c
make sure completions work across files
zth Nov 14, 2024
ce80c6c
filter pipe completions to only applicable functions
zth Nov 14, 2024
5ad0319
pipe complete only for functions that take the expected type as the f…
zth Nov 16, 2024
943b01f
start refactoring dot completion everywhere
zth Nov 20, 2024
ebc5d9e
refactor dot completion
zth Nov 28, 2024
8e2395e
add a few more synthetic
zth Nov 28, 2024
8e166ac
disable verbose log
zth Nov 28, 2024
2b3190c
cleanup
zth Nov 28, 2024
58cf089
pipe dot completion for builtins
zth Nov 28, 2024
70b7db6
Add example case (#1058)
nojaf Nov 29, 2024
931fd28
Additional completion tests (#1062)
nojaf Dec 19, 2024
e347146
make dot completion everywhere actually work
zth Dec 25, 2024
415eea9
do not care about ExtractedType now that we have incremental type che…
zth Dec 25, 2024
c715071
refactor to share pipe completion code logic
zth Dec 25, 2024
dfc3eb0
cleanup
zth Dec 25, 2024
4e4d03c
cleanup
zth Dec 25, 2024
0fa56aa
fix debug command
zth Dec 28, 2024
b6f7ccc
up rescript in test project
zth Dec 28, 2024
eb4cea5
change strategy for removing dot on completion
zth Dec 29, 2024
b1c6850
contonous dot completion
zth Dec 31, 2024
9c29710
handle dot completions on piped idents
zth Dec 31, 2024
9ac0817
handle scope
zth Dec 31, 2024
3d0a1c8
inline pipe completion logic again
zth Jan 2, 2025
bf7eeba
refactor
zth Jan 2, 2025
380e8a9
more compl spec
zth Jan 2, 2025
603b8d9
refactor
zth Jan 2, 2025
b5053bc
changelog
zth Jan 2, 2025
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
Prev Previous commit
Next Next commit
correctly insert completion item text removing the dot when selecting…
… a pipe function
  • Loading branch information
zth committed Jan 2, 2025
commit 4347fa3ccc49042faed24dced3e2e74408e908cd
29 changes: 25 additions & 4 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,8 @@ let rec digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos ~env
| {kind = Type {kind = Record fields}} :: _ -> Some fields
| _ -> None

let mkItem ?data name ~kind ~detail ~deprecated ~docstring =
let mkItem ?data ?(range : Location.t option) name ~kind ~detail ~deprecated
~docstring =
let docContent =
(match deprecated with
| None -> ""
Expand Down Expand Up @@ -682,6 +683,23 @@ let mkItem ?data name ~kind ~detail ~deprecated ~docstring =
insertTextFormat = None;
filterText = None;
data;
range =
(match range with
| None -> None
| Some range ->
Some
{
start =
{
line = range.loc_start.pos_lnum - 1;
character = range.loc_start.pos_cnum - range.loc_start.pos_bol;
};
end_ =
{
line = range.loc_end.pos_lnum - 1;
character = range.loc_end.pos_cnum - range.loc_end.pos_bol;
};
});
}

let completionToItem
Expand All @@ -696,9 +714,10 @@ let completionToItem
filterText;
detail;
env;
range;
} ~full =
let item =
mkItem name
mkItem name ?range
?data:(kindToData (full.file.uri |> Uri.toPath) kind)
~kind:(Completion.kindToInt kind)
~deprecated
Expand Down Expand Up @@ -950,13 +969,14 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
[Completion.create "dummy" ~env ~kind:(Completion.Value retType)]
| _ -> [])
| _ -> [])
| CPField (CPId {path; completionContext = Module}, fieldName) ->
| CPField {contextPath = CPId {path; completionContext = Module}; fieldName}
->
if Debug.verbose () then print_endline "[ctx_path]--> CPField: M.field";
(* M.field *)
path @ [fieldName]
|> getCompletionsForPath ~debug ~opens ~full ~pos ~exact
~completionContext:Field ~env ~scope
| CPField (cp, fieldName) -> (
| CPField {contextPath = cp; fieldName; fieldNameLoc} -> (
if Debug.verbose () then print_endline "[ctx_path]--> CPField";
let completionsForCtxPath =
cp
Expand Down Expand Up @@ -1054,6 +1074,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
|> List.hd);
insertText = Some nameWithPipe;
env;
range = Some fieldNameLoc;
}
| _ -> None)
| None -> []
Expand Down
72 changes: 51 additions & 21 deletions analysis/src/CompletionFrontEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -222,21 +222,26 @@ let rec exprToContextPathInner (e : Parsetree.expression) =
| Pexp_ident {txt; loc} ->
Some
(CPId {path = Utils.flattenLongIdent txt; completionContext = Value; loc})
| Pexp_field (e1, {txt = Lident name}) -> (
| Pexp_field (e1, {txt = Lident name; loc}) -> (
match exprToContextPath e1 with
| Some contextPath -> Some (CPField (contextPath, name))
| Some contextPath ->
Some (CPField {contextPath; fieldName = name; fieldNameLoc = loc})
| _ -> None)
| Pexp_field (_, {loc; txt = Ldot (lid, name)}) ->
(* Case x.M.field ignore the x part *)
Some
(CPField
( CPId
{
path = Utils.flattenLongIdent lid;
completionContext = Module;
loc;
},
name ))
{
contextPath =
CPId
{
path = Utils.flattenLongIdent lid;
completionContext = Module;
loc;
};
fieldName = name;
fieldNameLoc = loc;
})
| Pexp_send (e1, {txt}) -> (
match exprToContextPath e1 with
| None -> None
Expand Down Expand Up @@ -1130,29 +1135,54 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
| Lident name -> (
match exprToContextPath e with
| Some contextPath ->
let contextPath = Completable.CPField (contextPath, name) in
let contextPath =
Completable.CPField
{
contextPath;
fieldName = name;
fieldNameLoc = fieldName.loc;
}
in
setResult (Cpath contextPath)
| None -> ())
| Ldot (id, name) ->
(* Case x.M.field ignore the x part *)
let contextPath =
Completable.CPField
( CPId
{
loc = fieldName.loc;
path = Utils.flattenLongIdent id;
completionContext = Module;
},
if blankAfterCursor = Some '.' then
(* x.M. field ---> M. *) ""
else if name = "_" then ""
else name )
{
contextPath =
CPId
{
loc = fieldName.loc;
path = Utils.flattenLongIdent id;
completionContext = Module;
};
fieldName =
(if blankAfterCursor = Some '.' then
(* x.M. field ---> M. *) ""
else if name = "_" then ""
else name);
fieldNameLoc = fieldName.loc;
}
in
setResult (Cpath contextPath)
| Lapply _ -> ()
else if Loc.end_ e.pexp_loc = posBeforeCursor then
match exprToContextPath e with
| Some contextPath -> setResult (Cpath (CPField (contextPath, "")))
| Some contextPath ->
setResult
(Cpath
(CPField
{
contextPath;
fieldName = "";
fieldNameLoc =
{
loc_start = e.pexp_loc.loc_end;
loc_end = e.pexp_loc.loc_end;
loc_ghost = false;
};
}))
| None -> ())
| Pexp_apply ({pexp_desc = Pexp_ident compName}, args)
when Res_parsetree_viewer.is_jsx_expression expr ->
Expand Down
22 changes: 20 additions & 2 deletions analysis/src/Protocol.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type completionItem = {
insertText: string option;
documentation: markupContent option;
data: (string * string) list option;
range: range option;
}

type location = {uri: string; range: range}
Expand Down Expand Up @@ -142,7 +143,10 @@ let stringifyCompletionItem c =
| Some doc -> stringifyMarkupContent doc) );
("sortText", optWrapInQuotes c.sortText);
("filterText", optWrapInQuotes c.filterText);
("insertText", optWrapInQuotes c.insertText);
( "insertText",
match c.range with
| Some _ -> None
| None -> optWrapInQuotes c.insertText );
( "insertTextFormat",
match c.insertTextFormat with
| None -> None
Expand All @@ -156,6 +160,20 @@ let stringifyCompletionItem c =
(fields
|> List.map (fun (key, value) -> (key, Some (wrapInQuotes value)))
|> stringifyObject ~indentation:2) );
( "textEdit",
match c.range with
| Some range ->
Some
(stringifyObject
[
("range", Some (stringifyRange range));
( "newText",
optWrapInQuotes
(match c.insertText with
| None -> Some c.label
| v -> v) );
])
| None -> None );
]

let stringifyHover value =
Expand Down Expand Up @@ -282,7 +300,7 @@ let stringifyCodeAction ca =
(wrapInQuotes (codeActionKindToString ca.codeActionKind))
(ca.edit |> stringifyCodeActionEdit)

let stringifyHint hint =
let stringifyHint (hint : inlayHint) =
Printf.sprintf
{|{
"position": %s,
Expand Down
16 changes: 12 additions & 4 deletions analysis/src/SharedTypes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,11 @@ module Completable = struct
completionContext: completionContext;
loc: Location.t;
}
| CPField of contextPath * string
| CPField of {
contextPath: contextPath;
fieldName: string;
fieldNameLoc: Location.t;
}
| CPObj of contextPath * string
| CPAwait of contextPath
| CPPipe of {
Expand Down Expand Up @@ -696,7 +700,8 @@ module Completable = struct
| CPArray None -> "array"
| CPId {path; completionContext} ->
completionContextToString completionContext ^ list path
| CPField (cp, s) -> contextPathToString cp ^ "." ^ str s
| CPField {contextPath = cp; fieldName = s} ->
contextPathToString cp ^ "." ^ str s
| CPObj (cp, s) -> contextPathToString cp ^ "[\"" ^ s ^ "\"]"
| CPPipe {contextPath; id; inJsx} ->
contextPathToString contextPath
Expand Down Expand Up @@ -808,10 +813,12 @@ module Completion = struct
detail: string option;
typeArgContext: typeArgContext option;
data: (string * string) list option;
range: Location.t option;
}

let create ?data ?typeArgContext ?(includesSnippets = false) ?insertText ~kind
~env ?sortText ?deprecated ?filterText ?detail ?(docstring = []) name =
let create ?range ?data ?typeArgContext ?(includesSnippets = false)
?insertText ~kind ~env ?sortText ?deprecated ?filterText ?detail
?(docstring = []) name =
{
name;
env;
Expand All @@ -826,6 +833,7 @@ module Completion = struct
detail;
typeArgContext;
data;
range;
}

(* https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion *)
Expand Down
5 changes: 4 additions & 1 deletion analysis/tests/src/expected/CompletionFromModule.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ Path SomeModule.
"detail": "t => string",
"documentation": null,
"sortText": "getName",
"insertText": "->SomeModule.getName"
"textEdit": {
"range": {"start": {"line": 11, "character": 4}, "end": {"line": 11, "character": 4}},
"newText": "->SomeModule.getName"
}
}, {
"label": "name",
"kind": 5,
Expand Down