Source file render_tree.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
type block_status = [ `Idle | `Running ]
type selection_status =
[ `None | `Caret | `Range_single | `Range_start | `Range_end | `Range_middle ]
type block = {
id : int;
focused : bool;
status : block_status;
selection : selection_status;
content : Document.block_content;
}
type document = block list
type diff =
| Added of block
| Removed of block
| Updated of { before : block; after : block }
let classify_selection state idx block_id =
let open State in
match state.selection with
| No_selection -> `None
| Caret caret -> if caret.block_id = block_id then `Caret else `None
| Range { anchor; focus } -> (
match
( Document.index_of_block state.document ~block_id:anchor.block_id,
Document.index_of_block state.document ~block_id:focus.block_id )
with
| Some anchor_idx, Some focus_idx ->
let start_idx = min anchor_idx focus_idx in
let end_idx = max anchor_idx focus_idx in
if idx < start_idx || idx > end_idx then `None
else if start_idx = end_idx then `Range_single
else if idx = start_idx then `Range_start
else if idx = end_idx then `Range_end
else `Range_middle
| _ -> `None)
let of_state (state : State.t) : document =
let open State in
state.document
|> List.mapi (fun idx (blk : Document.block) ->
let status =
if State.is_block_running state blk.id then `Running else `Idle
in
let selection = classify_selection state idx blk.id in
{
id = blk.id;
focused = blk.focused;
status;
selection;
content = blk.content;
})
module Int_map = Map.Make (Int)
let to_map (doc : document) =
List.fold_left (fun acc blk -> Int_map.add blk.id blk acc) Int_map.empty doc
let diff before after =
let before_map = to_map before in
let after_map = to_map after in
let changes =
Int_map.fold
(fun id before_blk acc ->
match Int_map.find_opt id after_map with
| None -> Removed before_blk :: acc
| Some after_blk ->
if before_blk = after_blk then acc
else Updated { before = before_blk; after = after_blk } :: acc)
before_map []
in
Int_map.fold
(fun id after_blk acc ->
match Int_map.find_opt id before_map with
| None -> Added after_blk :: acc
| Some _ -> acc)
after_map changes
|> List.rev