Source file buffer_helper.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
open! Core
open! Import
let with_buffer sync_or_async contents ~f =
Current_buffer.set_temporarily_to_temp_buffer sync_or_async (fun () ->
Point.insert_text (contents |> Text.of_utf8_bytes);
f ())
;;
let with_buffer_and_point sync_or_async contents line_and_column ~f =
with_buffer sync_or_async contents ~f:(fun () ->
Point.goto_line_and_column line_and_column;
f ())
;;
let utf8_full_block_U2588 = "\xE2\x96\x88"
let show_buffer ~block_out =
let contents = Current_buffer.contents () |> Text.to_utf8_bytes in
Current_buffer.set_temporarily_to_temp_buffer Sync (fun () ->
Point.insert contents;
List.iter block_out ~f:(fun position ->
let min = Point.min () in
let max = Point.max () in
let start = Position.clamp_exn position ~min ~max in
let end_ = Position.clamp_exn (Position.add position 1) ~min ~max in
Point.goto_char start;
let contains_newline =
Current_buffer.contents ~start ~end_ ()
|> Text.to_utf8_bytes
|> String.is_substring ~substring:"\n"
in
Current_buffer.delete_region ~start ~end_;
Point.insert utf8_full_block_U2588;
if contains_newline then Point.insert "\n");
message (Current_buffer.contents () |> Text.to_utf8_bytes))
;;
let show_point () = show_buffer ~block_out:[ Point.get () ]
module Region = struct
type t =
{ start : Line_and_column.t
; end_ : Line_and_column.t
}
[@@deriving sexp_of]
end
open Region
let with_buffer_and_active_region sync_or_async contents { start; end_ } ~f =
with_buffer sync_or_async contents ~f:(fun () ->
Current_buffer.set_mark (Current_buffer.position_of_line_and_column start);
Point.goto_line_and_column end_;
f ())
;;
let show_active_region () =
match Current_buffer.active_region () with
| None -> print_s [%message "No region is active."]
| Some (start, end_) -> show_buffer ~block_out:[ start; end_ ]
;;
let show_with_overlay_text () =
Buffer.with_temp_buffer Sync (fun temp_buffer ->
let write before text after =
Current_buffer.set_temporarily Sync temp_buffer ~f:(fun () ->
Point.insert before;
Point.insert_text text;
Point.insert after)
in
let write_text_property_if_present overlay property_name =
match Overlay.get_property overlay property_name with
| exception _ -> ()
| s -> write "<overlay>" s "</overlay>"
in
Current_buffer.save_excursion Sync (fun () ->
Point.goto_min ();
let all_overlays = Overlay.in_ ~start:(Point.min ()) ~end_:(Point.max ()) in
let all_endpoints =
List.concat_map all_overlays ~f:(fun overlay ->
[ Overlay.start overlay; Overlay.end_ overlay ])
|> Position.Set.of_list
in
let rec loop () =
if Position.( < ) (Point.get ()) (Point.max ())
then (
let overlays_starting_here = ref [] in
let overlays_ending_here = ref [] in
let empty_overlays = ref [] in
List.iter all_overlays ~f:(fun o ->
let start = Overlay.start o in
let end_ = Overlay.end_ o in
if Position.equal start (Point.get ())
then
if Position.equal end_ (Point.get ())
then empty_overlays := o :: !empty_overlays
else overlays_starting_here := o :: !overlays_starting_here
else if Position.equal end_ (Point.get ())
then overlays_ending_here := o :: !overlays_ending_here);
let compare_overlay a b =
Comparable.lift
Int.compare
~f:(fun o -> Position.diff (Overlay.end_ o) (Overlay.start o))
a
b
in
let overlays_starting_here =
List.sort !overlays_starting_here ~compare:compare_overlay
in
let overlays_ending_here =
List.sort !overlays_ending_here ~compare:compare_overlay
in
let empty_overlays =
List.sort !empty_overlays ~compare:compare_overlay
in
List.iter (List.rev overlays_ending_here) ~f:(fun o ->
write_text_property_if_present o Text.Property_name.after_string);
List.iter empty_overlays ~f:(fun o ->
write_text_property_if_present o Text.Property_name.before_string;
write_text_property_if_present o Text.Property_name.after_string);
List.iter overlays_starting_here ~f:(fun o ->
write_text_property_if_present o Text.Property_name.before_string);
let () =
match
List.filter_map overlays_starting_here ~f:(fun o ->
match Overlay.get_property o Text.Property_name.invisible with
| exception _ -> None
| invisible ->
if Value.is_not_nil invisible then Some (Overlay.end_ o) else None)
|> List.max_elt ~compare:Position.compare
with
| Some end_of_invisibility
when
Position.( > ) end_of_invisibility (Point.get ()) ->
write
"<invisible>"
(Current_buffer.contents
~start:(Point.get ())
~end_:end_of_invisibility
~text_properties:true
())
"</invisible>";
Point.goto_char end_of_invisibility
| Some _ | None ->
let next_overlay_endpoint_or_end_of_buffer =
match
Set.to_sequence
all_endpoints
~greater_or_equal_to:(Position.add (Point.get ()) 1)
|> Sequence.hd
with
| Some next_overlay_endpoint -> next_overlay_endpoint
| None -> Point.max ()
in
write
""
(Current_buffer.contents
~start:(Point.get ())
~end_:next_overlay_endpoint_or_end_of_buffer
~text_properties:true
())
"";
Point.goto_char next_overlay_endpoint_or_end_of_buffer
in
loop ())
in
loop ();
Current_buffer.set_temporarily Sync temp_buffer ~f:(fun () ->
show_buffer ~block_out:[])))
;;
module Sample_input = struct
let table1 =
{|
┌──────────────────────────────────────┬─────┬──────┬────────┬───────────┐
│ feature │ CRs │ XCRs │ review │ next step │
├──────────────────────────────────────┼─────┼──────┼────────┼───────────┤
│ jane │ │ │ │ │
│ plugd │ │ │ │ fix build │
│ rewrite-flags │ 1 │ 1 │ 9 │ │
└──────────────────────────────────────┴─────┴──────┴────────┴───────────┘
|}
;;
let table2 =
{|
Features you own:
┌──────────────────────────┬─────┬──────┬───────┬───────────────────────┐
│ feature │ CRs │ XCRs │ #left │ next step │
├──────────────────────────┼─────┼──────┼───────┼───────────────────────┤
│ jane │ │ │ │ │
│ plugd │ │ │ │ fix build │
│ clean-up-obligations │ │ │ 3 │ review │
│ commander │ │ │ │ rebase, release │
│ versioned-types │ │ │ 1 │ review │
│ pipe-rpc │ │ │ 1 │ rebase, enable-review │
└──────────────────────────┴─────┴──────┴───────┴───────────────────────┘
|}
;;
end