Source file text_document.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
open Import
include struct
open Types
module DidOpenTextDocumentParams = DidOpenTextDocumentParams
module DocumentUri = DocumentUri
module Range = Range
module TextDocumentItem = TextDocumentItem
module TextDocumentContentChangeEvent = TextDocumentContentChangeEvent
module TextEdit = TextEdit
end
type invalid_utf = String_zipper.invalid_utf =
| Malformed of string
| Insufficient_input
exception Invalid_utf = String_zipper.Invalid_utf
type t =
{ languageId : string
;
mutable text : string option
; uri : DocumentUri.t
; version : int
; mutable zipper : String_zipper.t
; position_encoding : [ `UTF8 | `UTF16 ]
}
let position_encoding t = t.position_encoding
let make ~position_encoding
{ DidOpenTextDocumentParams.textDocument =
{ TextDocumentItem.languageId; text; uri; version }
} =
let zipper = String_zipper.of_string text in
{ text = Some text; position_encoding; zipper; uri; version; languageId }
let documentUri (t : t) = t.uri
let version (t : t) = t.version
let languageId (t : t) = t.languageId
let apply_change encoding sz (change : TextDocumentContentChangeEvent.t) =
match change.range with
| None -> String_zipper.of_string change.text
| Some range ->
String_zipper.apply_change sz range encoding ~replacement:change.text
let apply_content_changes ?version t changes =
let zipper =
List.fold_left ~f:(apply_change t.position_encoding) ~init:t.zipper changes
in
let version =
match version with
| None -> t.version
| Some version -> version
in
{ t with zipper; text = None; version }
let text t =
match t.text with
| Some text -> text
| None ->
let zipper, text = String_zipper.squash t.zipper in
t.text <- Some text;
t.zipper <- zipper;
text
module Edit_map = Map.Make (Position)
let add_edit map (change : TextEdit.t) =
Edit_map.update map ~key:change.range.start ~f:(function
| None -> Some [ change ]
| Some changes -> Some (change :: changes))
let apply_changes zipper encoding changes =
let simplified = List.fold_left changes ~init:Edit_map.empty ~f:add_edit in
let b = Buffer.create 0 in
let pos = ref Position.zero in
let zipper = String_zipper.goto_position zipper !pos encoding in
let zipper = ref zipper in
Edit_map.iter simplified ~f:(fun ~key:start ~data ->
assert (Position.compare start !pos >= 0);
zipper := String_zipper.goto_position !zipper !pos encoding;
let zipper' = String_zipper.goto_position !zipper start encoding in
String_zipper.add_buffer_between b !zipper zipper';
zipper := zipper';
List.rev data
|> List.iter ~f:(fun { TextEdit.newText; range } ->
assert (Position.compare range.end_ !pos >= 0);
pos := range.end_;
Buffer.add_string b newText));
let zipper = String_zipper.goto_position !zipper !pos encoding in
let zipper' = String_zipper.goto_end zipper in
String_zipper.add_buffer_between b zipper zipper';
Buffer.contents b
let set_version t ~version = { t with version }
let apply_text_document_edits t (edits : TextEdit.t list) =
let text = apply_changes t.zipper t.position_encoding edits in
let zipper = String_zipper.of_string text in
{ t with text = Some text; zipper }
let absolute_position t pos =
String_zipper.goto_position t.zipper pos t.position_encoding
|> String_zipper.offset
let absolute_range t (range : Range.t) =
let zipper =
String_zipper.goto_position t.zipper range.start t.position_encoding
in
let start = String_zipper.offset zipper in
let zipper =
String_zipper.goto_position zipper range.end_ t.position_encoding
in
let stop = String_zipper.offset zipper in
(start, stop)