-
Notifications
You must be signed in to change notification settings - Fork 124
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
Fix edge cases that prevent completion #1181
Closed
Closed
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
96376d1
Tests passing
faldor20 9bb112a
Added support for whitespace in completion
faldor20 0b1920e
Addded ability to have whitespace before or after the dot and test.
faldor20 cfde1e0
finished cleanup and added support for monadic bind.
faldor20 f6a031c
removed pointless regex
faldor20 bfddc86
reversed implimentation
faldor20 f84be2f
fixed everything other than combinators
faldor20 1fce0d6
fixed formatting and removed unnecissary import
faldor20 4d720d0
Misc fixes, names, formatting, etc converted to Re syntax for regex, …
faldor20 59e82fa
removed old prefix_parser
faldor20 a4c690b
renamed regexes
faldor20 abb05c9
Removed unnecessary Option extension
faldor20 5b07aca
spelling
faldor20 96c104e
converted to forward regex for simplicity
faldor20 cbaa820
Added Long file for benchmarking and removed unused benchmarks
faldor20 1841030
Merge branch 'master-origin'
faldor20 26476a6
Initial code for new-e2e tests for completion
faldor20 766509c
Finished adding completion tests
faldor20 0fbea39
converted last few missed tests
faldor20 b27e3cc
formatting
faldor20 b746bd5
removed old tests
faldor20 e7008b9
added interface
faldor20 c4249a8
fix bad interface
faldor20 6aa39f3
Merge branch 'master-origin'
faldor20 bdaa47c
Trying to get benchmarks to build fine
faldor20 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
let document = | ||
"let mem = ListLabels.mem\n\nlet _ = mem ~se" |> Merlin_kernel.Msource.make | ||
|
||
let long_document_text = | ||
{|let prefix_of_position ~short_path source position = | ||
let open Prefix_parser in | ||
match Msource.text source with | ||
| "" -> "" | ||
| text -> | ||
let end_of_prefix = | ||
let (`Offset index) = Msource.get_offset source position in | ||
min (String.length text - 1) (index - 1) | ||
in | ||
let prefix_text = | ||
let pos = | ||
(*clamp the length of a line to process at 500 chars, this is just a | ||
reasonable limit for regex performance*) | ||
max 0 (end_of_prefix - 500) | ||
in | ||
String.sub text ~pos ~len:(end_of_prefix + 1 - pos) | ||
(*because all whitespace is semantically the same we convert it all to | ||
spaces for easier regex matching*) | ||
|> String.rev_map ~f:(fun x -> if x = '\n' || x = '\t' then ' ' else x) | ||
in | ||
|
||
let reconstructed_prefix = | ||
try_parse_with_regex prefix_text | ||
|> Option.value ~default:"" | ||
|> String.rev_filter ~f:(fun x -> x <> ' ') | ||
in | ||
|
||
if short_path then | ||
match String.split_on_char reconstructed_prefix ~sep:'.' |> List.last with | ||
| Some s -> s | ||
| None -> reconstructed_prefix | ||
else reconstructed_prefix | ||
|
||
let suffix_of_position source position = | ||
match Msource.text source with | ||
| "" -> "" | ||
| text -> | ||
let (`Offset index) = Msource.get_offset source position in | ||
let len = String.length text in | ||
if index >= len then "" | ||
else | ||
let from = index in | ||
let len = | ||
let ident_char = function | ||
| 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '\'' | '_' -> true | ||
| _ -> false | ||
in | ||
let until = | ||
String.findi ~from text ~f:(fun c -> not (ident_char c)) | ||
|> Option.value ~default:len | ||
in | ||
until - from | ||
in | ||
String.sub text ~pos:from ~len | ||
|
||
let reconstruct_ident source position = | ||
let prefix = prefix_of_position ~short_path:false source position in | ||
let suffix = suffix_of_position source position in | ||
let ident = prefix ^ suffix in | ||
Option.some_if (ident <> "") ident | ||
|
||
let range_prefix (lsp_position : Position.t) prefix : Range.t = | ||
let start = | ||
let len = String.length prefix in | ||
let character = lsp_position.character - len in | ||
{ lsp_position with character } | ||
in | ||
{ Range.start; end_ = lsp_position } | ||
|
||
let sortText_of_index idx = Printf.sprintf "%04d" idx | ||
|
||
module Complete_by_prefix = struct | ||
let completionItem_of_completion_entry idx | ||
(entry : Query_protocol.Compl.entry) ~compl_params ~range ~deprecated = | ||
let kind = completion_kind entry.kind in | ||
let textEdit = `TextEdit { TextEdit.range; newText = entry.name } in | ||
CompletionItem.create | ||
~label:entry.name | ||
?kind | ||
~detail:entry.desc | ||
?deprecated:(Option.some_if deprecated entry.deprecated) | ||
(* Without this field the client is not forced to respect the order | ||
provided by merlin. *) | ||
~sortText:(sortText_of_index idx) | ||
?data:compl_params | ||
~textEdit | ||
() | ||
|
||
let dispatch_cmd ~prefix position pipeline = | ||
let complete = | ||
Query_protocol.Complete_prefix (prefix, position, [], false, true) | ||
in | ||
Query_commands.dispatch pipeline comp | ||
|} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
(executables | ||
(names ocaml_lsp_bench) | ||
(libraries | ||
ocaml_lsp_server | ||
core_unix.command_unix | ||
merlin-lib.kernel | ||
base | ||
core | ||
core_bench) | ||
(preprocess | ||
(pps ppx_bench))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
open Ocaml_lsp_server | ||
open Core | ||
open Core_bench | ||
|
||
let () = | ||
let open Documents in | ||
let long_document = long_document_text |> Merlin_kernel.Msource.make in | ||
let position = `Logical (3, 15) in | ||
let long_position = `Logical (92, 41) in | ||
Command_unix.run | ||
(Bench.make_command | ||
[ Bench.Test.create ~name:"get_prefix" (fun _ -> | ||
Testing.Compl.prefix_of_position | ||
~short_path:false | ||
document | ||
position | ||
|> ignore) | ||
; Bench.Test.create ~name:"get_prefix_long" (fun _ -> | ||
Testing.Compl.prefix_of_position | ||
~short_path:false | ||
long_document | ||
long_position | ||
|> ignore) | ||
; Bench.Test.create ~name:"get_offset_long" (fun _ -> | ||
Merlin_kernel.Msource.get_offset long_document long_position | ||
|> ignore) | ||
]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
faldor20 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
open Re | ||
|
||
(*Regex based parser*) | ||
let whiteSpace = set "\n\t " | ||
|
||
let name_char = | ||
Re.alt [ rg 'a' 'z'; rg 'A' 'Z'; rg '0' '9'; char '_'; char '\'' ] | ||
|
||
let name_with_dot = | ||
Re.seq [ name_char; whiteSpace |> rep; char '.'; whiteSpace |> rep ] | ||
|
||
let core_operator_str = {|$&*+-/=>@^||} | ||
|
||
let operator = core_operator_str ^ {|~!?%<:.|} | ||
|
||
let infix = set (operator ^ "#") | ||
|
||
let name_or_label = | ||
compile | ||
(seq | ||
[ alt [ set "~?``"; str "let%"; str "and%" ] |> opt | ||
; alt [ name_char; name_with_dot ] |> rep1 | ||
; stop | ||
]) | ||
|
||
(** matches let%lwt and let* style expressions. See | ||
here:https://v2.ocaml.org/manual/bindingops.html *) | ||
let monadic_bind = | ||
compile | ||
(seq | ||
[ alt [ str "let"; str "and" ] | ||
; alt [ infix |> rep1; seq [ name_char |> rep1; char '%' ] ] | ||
; stop | ||
]) | ||
|
||
let infix_operator = compile (seq [ infix |> rep1; stop ]) | ||
|
||
open Import | ||
|
||
let try_parse_with_regex ?pos ?len text = | ||
(*Attempt to match each of our possible prefix types, the order is important | ||
because there is some overlap between the regexs*) | ||
let matched = | ||
List.find_map | ||
[ name_or_label; monadic_bind; infix_operator ] | ||
~f:(fun regex -> Re.exec_opt ?pos ?len regex text) | ||
in | ||
matched |> Option.map ~f:(fun x -> Group.get x 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
(**Try's the parse the incoming string for a prefix. The string should be the | ||
source code ending at the prefix position. pos and len set the range for the | ||
regex to operate on*) | ||
val try_parse_with_regex : ?pos:int -> ?len:int -> string -> string option |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
(**WARNING: This is for internal use in testing only *) | ||
|
||
module Compl = Compl | ||
module Merlin_kernel = Merlin_kernel | ||
module Prefix_parser = Prefix_parser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this for the tests?