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
1 change: 0 additions & 1 deletion language-server/dm/document.ml
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,6 @@ let validate_document ({ parsed_loc; raw_doc; cancel_handle } as document) =
let handle_invalidate {parsed; errors; parsed_comments; stop; top_id; started; previous_document} document =
let end_ = Unix.gettimeofday ()in
let time = end_ -. started in
(* log (fun () -> Format.sprintf "Parsing phase ended in %5.3f" time); *)
log (fun () -> Format.sprintf "Parsing phase ended in %5.3f\n%!" time);
let new_sentences = List.rev parsed in
let new_comments = List.rev parsed_comments in
Expand Down
58 changes: 44 additions & 14 deletions language-server/dm/rawDocument.ml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ let text t = t.text

let line_text raw i =
if i + 1 < Array.length raw.lines then
String.sub raw.text (raw.lines.(i)) (raw.lines.(i+1) - raw.lines.(i))
(raw.lines.(i), raw.lines.(i+1) - raw.lines.(i))
else
String.sub raw.text (raw.lines.(i)) (String.length raw.text - raw.lines.(i))
(raw.lines.(i), String.length raw.text - raw.lines.(i))

let get_character_pos linestr loc =
let get_character_pos raw (i,e) loc =
let rec loop d =
if Uutf.decoder_byte_count d >= loc then
Uutf.decoder_count d
Expand All @@ -44,20 +44,48 @@ let get_character_pos linestr loc =
| `Uchar _ -> loop d
| `Malformed _ -> loop d
| `End -> Uutf.decoder_count d
| `Await -> assert false
| `Await -> Uutf.Manual.src d (Bytes.unsafe_of_string "") 0 0; loop d
in
let nln = `Readline (Uchar.of_int 0x000A) in
let encoding = `UTF_8 in
loop (Uutf.decoder ~nln ~encoding (`String linestr))
let d = Uutf.decoder ~nln ~encoding `Manual in
(* Printf.eprintf "lookup %d|%s\n" loc (String.sub raw.text i e); *)
Uutf.Manual.src d (Bytes.unsafe_of_string raw.text) i e;
loop d

let position_of_loc raw loc =
let rec position_of_loc_bisect raw loc i m n len =
(* Printf.eprintf "%i | %i(%d) <= %i(%d) < %i(%d)\n" loc m raw.lines.(m) i raw.lines.(i) n raw.lines.(n); *)
if i = len || i = n || raw.lines.(i) <= loc && loc < raw.lines.(i+1) then i
else if loc < raw.lines.(i) then position_of_loc_bisect raw loc (m + (max 1 ((i - m) / 2))) m i len
else position_of_loc_bisect raw loc (i + (max 1 ((n - i) / 2))) i n len


let position_of_loc_bisect raw loc =
let nlines = Array.length raw.lines in
let line = if loc = 0 then 0 else position_of_loc_bisect raw loc (nlines/2) 0 (nlines-1) (nlines-1) in
(* Printf.eprintf "line bisect: %d\n" line; *)
let char = get_character_pos raw (line_text raw line) (loc - raw.lines.(line)) in
Position.{ line = line; character = char }

let position_of_loc = position_of_loc_bisect

(* let position_of_loc raw loc =
let i = ref 0 in
while (!i < Array.length raw.lines && raw.lines.(!i) <= loc) do incr(i) done;
let line = !i - 1 in
let char = get_character_pos (line_text raw line) (loc - raw.lines.(line)) in
Position.{ line = line; character = char }
(* Printf.eprintf "line linear: %d\n" line; *)
let char = get_character_pos raw (line_text raw line) (loc - raw.lines.(line)) in
Position.{ line = line; character = char }

let get_character_loc linestr pos =
let position_of_loc r l =
assert(l>=0);
let p1 = position_of_loc_bisect r l in
let p2 = position_of_loc r l in
(* Printf.eprintf "%d=%d, %d=%d\n" p1.Position.character p2.Position.character p1.Position.line p2.Position.line; *)
assert(p1=p2);
p1
*)
let get_character_loc raw (i,e) pos =
let rec loop d =
if Uutf.decoder_count d >= pos then
Uutf.decoder_byte_count d
Expand All @@ -66,24 +94,26 @@ let get_character_loc linestr pos =
| `Uchar _ -> loop d
| `Malformed _ -> loop d
| `End -> Uutf.decoder_byte_count d
| `Await -> assert false
| `Await -> Uutf.Manual.src d (Bytes.unsafe_of_string "") 0 0; loop d
in
let nln = `Readline (Uchar.of_int 0x000A) in
let encoding = `UTF_8 in
loop (Uutf.decoder ~nln ~encoding (`String linestr))
let d = Uutf.decoder ~nln ~encoding `Manual in
Uutf.Manual.src d (Bytes.unsafe_of_string raw.text) i e;
loop d

let loc_of_position raw Position.{ line; character } =
let linestr = line_text raw line in
let charloc = get_character_loc linestr character in
let charloc = get_character_loc raw linestr character in
raw.lines.(line) + charloc

let end_loc raw =
String.length raw.text

let range_of_loc raw loc =
let open Range in
{ start = position_of_loc raw loc.Loc.bp;
end_ = position_of_loc raw loc.Loc.ep;
{ start = position_of_loc_bisect raw loc.Loc.bp;
end_ = position_of_loc_bisect raw loc.Loc.ep;
}

let word_at_position raw pos : string option =
Expand Down
14 changes: 7 additions & 7 deletions language-server/tests/d_perf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let edit_text doc ~start ~stop text =
let range = Lsp.Types.Range.{ start; end_ } in
Document.apply_text_edits doc [range, text]

let size = 3_000 let adjust = 5 + size
let size = 30_000 let adjust = 5 + size

let validate_document parsed_document =
let doc, events = Document.validate_document parsed_document in
Expand All @@ -27,16 +27,16 @@ let checkpoint () =
let%test_unit "diff: huge doc" =
let t0 = checkpoint () in
let text = Stdlib.String.concat ".\n" (Stdlib.List.init size (fun _ -> "Definition x := 3")) in
let edit = Random.int (String.length text) in
let edit = String.length text / 2 in
let Document.{parsed_document} = init_and_parse_test_doc ~steps:(size+adjust) ~text () in
let t1 = checkpoint () in
let parsed_document = edit_text parsed_document ~start:edit ~stop:edit "x" in
let _ = validate_document parsed_document in
let { Document.parsed_document } = validate_document parsed_document in
let t2 = checkpoint () in
let parsed_document = edit_text parsed_document ~start:edit ~stop:edit "" in
let _ = validate_document parsed_document in
let o = Document.outline parsed_document in
let t3 = checkpoint () in
[%test_pred: int] (fun x -> x + 3 >= size && x <=size) (List.length o); (* the error *)
Stdlib.Printf.eprintf "full parse: %5.3f\n" (t1 -. t0);
Stdlib.Printf.eprintf "edit: %5.3f\n" (t2 -. t1);
Stdlib.Printf.eprintf "edit: %5.3f\n" (t3 -. t2);
Stdlib.Printf.eprintf "edit: %5.3f \n" (t2 -. t1);
Stdlib.Printf.eprintf "outline: %5.3f\n" (t3 -. t2);
()
37 changes: 37 additions & 0 deletions language-server/tests/rd_tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
open Base

type raw = { lines : int array }

let rec position_of_loc_bisect raw loc i m n len =
(* Printf.eprintf "%i | %i(%d) <= %i(%d) < %i(%d)\n" loc m raw.lines.(m) i raw.lines.(i) n raw.lines.(n); *)
if i = len || i = n || raw.lines.(i) <= loc && loc < raw.lines.(i+1) then i
else if loc < raw.lines.(i) then position_of_loc_bisect raw loc (m + (max 1 ((i - m) / 2))) m i len
else position_of_loc_bisect raw loc (i + (max 1 ((n - i) / 2))) i n len

let go raw loc =
let nlines = Array.length raw.lines in
let line = if loc = 0 then 0 else position_of_loc_bisect raw loc (nlines/2) 0 (nlines-1) (nlines-1) in
line

let raw = { lines = Array.init 5 ~f:(fun i -> i * 5) }

let%test_unit "bisect hole" =
[%test_eq: int] (go raw 0) 0;
let last = ref 0 in
for i = 0 to 41 do
let p = go raw i in
[%test_pred: int] ((<=) !last) p;
last := p;
done

let raw = { lines = Array.init 5 ~f:(fun i -> i) }

let%test_unit "bisect hole" =
[%test_eq: int] (go raw 0) 0;
let last = ref 0 in
for i = 0 to 41 do
let p = go raw i in
[%test_pred: int] ((<=) !last) p;
last := p;
done

Loading