summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <undyamon@disroot.org>2024-01-28 23:42:12 +0100
committerFederico Igne <undyamon@disroot.org>2024-01-28 23:42:12 +0100
commitf5c33507a74d83692c028d1e1659d3506399138e (patch)
tree15abadcda66931770003a7ec5b403695f4f81fd0
parent633fb26ed21f7208517aa29dbaab9f0cf3bb2047 (diff)
downloadsandy-f5c33507a74d83692c028d1e1659d3506399138e.tar.gz
sandy-f5c33507a74d83692c028d1e1659d3506399138e.zip
feat: add non-linear change history with undo/redoHEADmaster
-rw-r--r--lib/command.ml17
-rw-r--r--lib/editor.ml106
-rw-r--r--lib/editorBuffer.ml17
3 files changed, 123 insertions, 17 deletions
diff --git a/lib/command.ml b/lib/command.ml
index 2d7b51b..6439165 100644
--- a/lib/command.ml
+++ b/lib/command.ml
@@ -17,6 +17,10 @@ type operation =
17 | Search 17 | Search
18 | Search_rev 18 | Search_rev
19 | Goto 19 | Goto
20 | Undo
21 | Redo
22 | Earlier
23 | Later
20 24
21type scope = Line | To_bol | To_eol | Down | Left | Right | Up 25type scope = Line | To_bol | To_eol | Down | Left | Right | Up
22 26
@@ -85,6 +89,8 @@ let instant_operation =
85 Key 'X'; 89 Key 'X';
86 Key 'p'; 90 Key 'p';
87 Key 'x'; 91 Key 'x';
92 Key 'u';
93 Ctrl 'R';
88 ] 94 ]
89 95
90let chord_operation = [ Key 'c'; Key 'd'; Key 'y' ] 96let chord_operation = [ Key 'c'; Key 'd'; Key 'y' ]
@@ -101,6 +107,8 @@ let to_op = function
101 | Key 'P' -> Paste_before 107 | Key 'P' -> Paste_before
102 | Key 'x' -> Erase_after 108 | Key 'x' -> Erase_after
103 | Key 'X' -> Erase_before 109 | Key 'X' -> Erase_before
110 | Key 'u' -> Undo
111 | Ctrl 'R' -> Redo
104 | _ -> failwith "Invalid operation in chord." 112 | _ -> failwith "Invalid operation in chord."
105 113
106let is_chord_operation k = List.mem ~equal:Poly.equal chord_operation k 114let is_chord_operation k = List.mem ~equal:Poly.equal chord_operation k
@@ -129,6 +137,15 @@ let n_stream =
129 (`start, shortcut ~r (to_op k)) 137 (`start, shortcut ~r (to_op k))
130 | `chord_fst_n (r, n), k when is_instant_operation k -> 138 | `chord_fst_n (r, n), k when is_instant_operation k ->
131 (`start, shortcut ?r ~n (to_op k)) 139 (`start, shortcut ?r ~n (to_op k))
140 (* Special operations *)
141 | `start, Key 'g' -> (`special (None, None), Partial k)
142 | `chord_reg r, Key 'g' -> (`special (Some r, None), Partial k)
143 | `chord_fst_n (r, n), Key 'g' -> (`special (r, Some n), Partial k)
144 | `special (r, n), Key 'g' ->
145 let n = Option.value ~default:0 n in
146 (`start, shortcut ?r ~n Goto)
147 | `special (r, n), Key '-' -> (`start, shortcut ?r ?n Earlier)
148 | `special (r, n), Key '+' -> (`start, shortcut ?r ?n Later)
132 (* Chord operation (first) *) 149 (* Chord operation (first) *)
133 | `start, k when is_chord_operation k -> 150 | `start, k when is_chord_operation k ->
134 (`chord_cmd (None, None, to_op k), Partial k) 151 (`chord_cmd (None, None, to_op k), Partial k)
diff --git a/lib/editor.ml b/lib/editor.ml
index ea2e68a..315067b 100644
--- a/lib/editor.ml
+++ b/lib/editor.ml
@@ -14,7 +14,7 @@ type editor = {
14 mode : Mode.t; 14 mode : Mode.t;
15 offset : int * int; 15 offset : int * int;
16 cursor : cursor; 16 cursor : cursor;
17 buffer : Buffer.t; 17 buffer : Buffer.t Tipper.t;
18 rendered : bool; 18 rendered : bool;
19 istream : Command.t Sequence.t; 19 istream : Command.t Sequence.t;
20 nstream : Command.t Sequence.t; 20 nstream : Command.t Sequence.t;
@@ -39,7 +39,8 @@ let init (c : Config.t) : editor =
39 buffer = 39 buffer =
40 List.hd c.files 40 List.hd c.files
41 |> Option.map ~f:Buffer.from_file 41 |> Option.map ~f:Buffer.from_file
42 |> Option.value ~default:Buffer.empty; 42 |> Option.value_or_thunk ~default:Buffer.empty
43 |> Tipper.create;
43 rendered = true; 44 rendered = true;
44 istream = Command.i_stream; 45 istream = Command.i_stream;
45 nstream = Command.n_stream; 46 nstream = Command.n_stream;
@@ -59,10 +60,11 @@ let statusbar e =
59 let w = e.term.size |> snd in 60 let w = e.term.size |> snd in
60 let status = 61 let status =
61 let mode = e.mode |> Mode.to_string |> sequence_of_string in 62 let mode = e.mode |> Mode.to_string |> sequence_of_string in
62 let lsize = Sequence.length mode 63 let lsize = Sequence.length mode in
63 and c = e.buffer.kind |> Buffer.string_of_kind |> sequence_of_string 64 let buf = Tipper.focus e.buffer in
64 and br, bc = Buffer.size e.buffer 65 let c = buf.kind |> Buffer.string_of_kind |> sequence_of_string
65 and cr, cc = Buffer.cursor ~rendered:false e.buffer in 66 and br, bc = Buffer.size buf
67 and cr, cc = Buffer.cursor ~rendered:false buf in
66 let perc = 68 let perc =
67 match cr with 69 match cr with
68 | 0 -> "Top" 70 | 0 -> "Top"
@@ -136,15 +138,25 @@ module Action = struct
136 let dx, dy = e.offset and rs, cs = e.term.size in 138 let dx, dy = e.offset and rs, cs = e.term.size in
137 (* Limit cursor to buffer view *) 139 (* Limit cursor to buffer view *)
138 let rs = rs - e.status_size in 140 let rs = rs - e.status_size in
139 let cx, cy = Buffer.cursor e.buffer in 141 let cx, cy = e.buffer |> Tipper.focus |> Buffer.cursor in
140 let dx' = Int.clamp_exn ~min:(cx - rs + 1) ~max:cx dx 142 let dx' = Int.clamp_exn ~min:(cx - rs + 1) ~max:cx dx
141 and dy' = Int.clamp_exn ~min:(cy - cs + 1) ~max:cy dy in 143 and dy' = Int.clamp_exn ~min:(cy - cs + 1) ~max:cy dy in
142 { e with cursor = (cx - dx' + 1, cy - dy' + 1); offset = (dx', dy') } 144 { e with cursor = (cx - dx' + 1, cy - dy' + 1); offset = (dx', dy') }
143 in 145 in
144 modify ~f:aux 146 modify ~f:aux
145 147
146 let get_focused_buffer e = (e.buffer, e) 148 let get_focused_buffer_history e = (e.buffer, e)
147 let set_focused_buffer b e = ((), { e with buffer = b }) 149
150 let set_focused_buffer_history h =
151 (fun e -> ((), { e with buffer = h })) *> update_cursor
152
153 let on_focused_buffer_history f =
154 get_focused_buffer_history >>| f >>= set_focused_buffer_history
155
156 let get_focused_buffer e = (Tipper.focus e.buffer, e)
157
158 let set_focused_buffer b e =
159 ((), { e with buffer = Tipper.set_focus b e.buffer })
148 160
149 let on_focused_buffer f = 161 let on_focused_buffer f =
150 let* b = get_focused_buffer in 162 let* b = get_focused_buffer in
@@ -196,7 +208,7 @@ module Action = struct
196 in 208 in
197 let ssize = e.status_size in 209 let ssize = e.status_size in
198 let bufview = 210 let bufview =
199 e.buffer 211 e.buffer |> Tipper.focus
200 |> limit x y (r - ssize) c 212 |> limit x y (r - ssize) c
201 |> Text.extend ~fill r 213 |> Text.extend ~fill r
202 |> Fn.flip Sequence.take (r - ssize) 214 |> Fn.flip Sequence.take (r - ssize)
@@ -246,6 +258,48 @@ module Action = struct
246 set_message (Printf.sprintf "Pattern not found: %s" word) 258 set_message (Printf.sprintf "Pattern not found: %s" word)
247 | Some (r, c) -> Buffer.Action.goto ~r ~c |> on_focused_buffer 259 | Some (r, c) -> Buffer.Action.goto ~r ~c |> on_focused_buffer
248 260
261 (* History *)
262 let take_buffer_snapshot =
263 let* h = get_focused_buffer_history in
264 let buf = { (Tipper.focus h) with last_modified = Unix.gettimeofday () } in
265 let h = Tipper.(h |> push (create buf) |> down) in
266 set_focused_buffer_history h
267
268 let undo =
269 let* h = get_focused_buffer_history in
270 if Tipper.is_root h then set_message "Already at the oldest change"
271 else set_focused_buffer_history (Tipper.up h)
272
273 let redo =
274 let* h = get_focused_buffer_history in
275 if Tipper.is_leaf h then set_message "Already at the newest change"
276 else set_focused_buffer_history (Tipper.down h)
277
278 let timetravel ?(later = false) ?(_secs = 0.) =
279 let last_modified (n : Buffer.t Tipper.t) =
280 (Tipper.focus n).last_modified
281 in
282 let find ts h =
283 let f a t =
284 let tmax =
285 if later then
286 Option.(map ~f:last_modified a |> value ~default:Float.max_value)
287 else ts
288 in
289 let tmin =
290 if later then ts
291 else Option.(map ~f:last_modified a |> value ~default:0.)
292 and cur = last_modified t in
293 if Float.(tmin < cur && cur < tmax) then Some t else a
294 in
295 Tipper.fold ~a:None ~f h
296 in
297 let* h = get_focused_buffer_history in
298 let ts = last_modified h in
299 match find ts (Tipper.root h) with
300 | None -> set_message "Already at the oldest change"
301 | Some h -> set_focused_buffer_history h
302
249 (* Debug *) 303 (* Debug *)
250 let get_rendered e = (e.rendered, e) 304 let get_rendered e = (e.rendered, e)
251 let set_rendered r e = ((), { e with rendered = r }) 305 let set_rendered r e = ((), { e with rendered = r })
@@ -372,6 +426,7 @@ let handle_normal_command c =
372 (* Change *) 426 (* Change *)
373 | Shortcut (r, n, Change) -> 427 | Shortcut (r, n, Change) ->
374 let n = Option.value ~default:1 n - 1 in 428 let n = Option.value ~default:1 n - 1 in
429 let* () = take_buffer_snapshot in
375 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in 430 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in
376 let* () = set_register ?r (Glyphwise out) in 431 let* () = set_register ?r (Glyphwise out) in
377 set_mode Insert 432 set_mode Insert
@@ -383,6 +438,7 @@ let handle_normal_command c =
383 and* () = insert_line ~before:true *> move_up in 438 and* () = insert_line ~before:true *> move_up in
384 return out 439 return out
385 in 440 in
441 let* () = take_buffer_snapshot in
386 let* out = act |> on_focused_buffer in 442 let* out = act |> on_focused_buffer in
387 let* () = set_register ?r (Linewise out) in 443 let* () = set_register ?r (Linewise out) in
388 set_mode Insert 444 set_mode Insert
@@ -394,16 +450,19 @@ let handle_normal_command c =
394 and* () = insert_line ~before:true *> move_up in 450 and* () = insert_line ~before:true *> move_up in
395 return out 451 return out
396 in 452 in
453 let* () = take_buffer_snapshot in
397 let* out = act |> on_focused_buffer in 454 let* out = act |> on_focused_buffer in
398 let* () = set_register ?r (Linewise out) in 455 let* () = set_register ?r (Linewise out) in
399 set_mode Insert 456 set_mode Insert
400 | Chord (r, n1, Change, n2, Left) -> 457 | Chord (r, n1, Change, n2, Left) ->
401 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 458 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
459 let* () = take_buffer_snapshot in
402 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in 460 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in
403 let* () = set_register ?r (Glyphwise out) in 461 let* () = set_register ?r (Glyphwise out) in
404 set_mode Insert 462 set_mode Insert
405 | Chord (r, n1, Change, n2, Right) -> 463 | Chord (r, n1, Change, n2, Right) ->
406 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 464 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
465 let* () = take_buffer_snapshot in
407 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in 466 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in
408 let* () = set_register ?r (Glyphwise out) in 467 let* () = set_register ?r (Glyphwise out) in
409 set_mode Insert 468 set_mode Insert
@@ -415,41 +474,50 @@ let handle_normal_command c =
415 and* () = insert_line ~before:true *> move_up in 474 and* () = insert_line ~before:true *> move_up in
416 return out 475 return out
417 in 476 in
477 let* () = take_buffer_snapshot in
418 let* out = act |> on_focused_buffer in 478 let* out = act |> on_focused_buffer in
419 let* () = set_register ?r (Linewise out) in 479 let* () = set_register ?r (Linewise out) in
420 set_mode Insert 480 set_mode Insert
421 | Chord (r, _, Change, _, To_bol) -> 481 | Chord (r, _, Change, _, To_bol) ->
482 let* () = take_buffer_snapshot in
422 let* out = Buffer.Action.delete_to_bol |> on_focused_buffer in 483 let* out = Buffer.Action.delete_to_bol |> on_focused_buffer in
423 let* () = set_register ?r (Glyphwise out) in 484 let* () = set_register ?r (Glyphwise out) in
424 set_mode Insert 485 set_mode Insert
425 | Chord (r, n1, Change, n2, To_eol) -> 486 | Chord (r, n1, Change, n2, To_eol) ->
426 let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in 487 let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in
488 let* () = take_buffer_snapshot in
427 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in 489 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in
428 let* () = set_register ?r (Glyphwise out) in 490 let* () = set_register ?r (Glyphwise out) in
429 set_mode Insert 491 set_mode Insert
430 (* Delete *) 492 (* Delete *)
431 | Shortcut (r, n, Delete) -> 493 | Shortcut (r, n, Delete) ->
432 let n = Option.value ~default:1 n - 1 in 494 let n = Option.value ~default:1 n - 1 in
495 let* () = take_buffer_snapshot in
433 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in 496 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in
434 set_register ?r (Glyphwise out) 497 set_register ?r (Glyphwise out)
435 | Chord (r, n1, Delete, n2, Line) -> 498 | Chord (r, n1, Delete, n2, Line) ->
436 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 499 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
500 let* () = take_buffer_snapshot in
437 let* out = Buffer.Action.delete_lines ~n |> on_focused_buffer in 501 let* out = Buffer.Action.delete_lines ~n |> on_focused_buffer in
438 set_register ?r (Linewise out) 502 set_register ?r (Linewise out)
439 | Chord (r, n1, Delete, n2, Down) -> 503 | Chord (r, n1, Delete, n2, Down) ->
440 let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in 504 let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in
505 let* () = take_buffer_snapshot in
441 let* out = Buffer.Action.delete_lines ~n |> on_focused_buffer in 506 let* out = Buffer.Action.delete_lines ~n |> on_focused_buffer in
442 set_register ?r (Linewise out) 507 set_register ?r (Linewise out)
443 | Chord (r, n1, Delete, n2, Left) -> 508 | Chord (r, n1, Delete, n2, Left) ->
444 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 509 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
510 let* () = take_buffer_snapshot in
445 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in 511 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in
446 set_register ?r (Glyphwise out) 512 set_register ?r (Glyphwise out)
447 | Chord (r, n1, Delete, n2, Right) -> 513 | Chord (r, n1, Delete, n2, Right) ->
448 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 514 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
515 let* () = take_buffer_snapshot in
449 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in 516 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in
450 set_register ?r (Glyphwise out) 517 set_register ?r (Glyphwise out)
451 | Chord (r, n1, Delete, n2, Up) -> 518 | Chord (r, n1, Delete, n2, Up) ->
452 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in 519 let n = Option.(value ~default:1 n1 * value ~default:1 n2) in
520 let* () = take_buffer_snapshot in
453 let* out = 521 let* out =
454 Buffer.Action.(move_up ~n *> delete_lines ~n:(n + 1)) 522 Buffer.Action.(move_up ~n *> delete_lines ~n:(n + 1))
455 |> on_focused_buffer 523 |> on_focused_buffer
@@ -457,37 +525,47 @@ let handle_normal_command c =
457 set_register ?r (Linewise out) 525 set_register ?r (Linewise out)
458 | Shortcut (r, n, Erase_before) -> 526 | Shortcut (r, n, Erase_before) ->
459 let n = Option.value ~default:1 n in 527 let n = Option.value ~default:1 n in
528 let* () = take_buffer_snapshot in
460 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in 529 let* out = Buffer.Action.delete_before ~n |> on_focused_buffer in
461 set_register ?r (Glyphwise out) 530 set_register ?r (Glyphwise out)
462 | Shortcut (r, n, Erase_after) -> 531 | Shortcut (r, n, Erase_after) ->
463 let n = Option.value ~default:1 n in 532 let n = Option.value ~default:1 n in
533 let* () = take_buffer_snapshot in
464 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in 534 let* out = Buffer.Action.delete_after ~n |> on_focused_buffer in
465 set_register ?r (Glyphwise out) 535 set_register ?r (Glyphwise out)
466 | Chord (r, _, Delete, _, To_bol) -> 536 | Chord (r, _, Delete, _, To_bol) ->
537 let* () = take_buffer_snapshot in
467 let* out = Buffer.Action.delete_to_bol |> on_focused_buffer in 538 let* out = Buffer.Action.delete_to_bol |> on_focused_buffer in
468 set_register ?r (Glyphwise out) 539 set_register ?r (Glyphwise out)
469 | Chord (r, n1, Delete, n2, To_eol) -> 540 | Chord (r, n1, Delete, n2, To_eol) ->
470 let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in 541 let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in
542 let* () = take_buffer_snapshot in
471 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in 543 let* out = Buffer.Action.delete_to_eol ~n |> on_focused_buffer in
472 set_register ?r (Glyphwise out) 544 set_register ?r (Glyphwise out)
473 (* Paste *) 545 (* Paste *)
474 | Shortcut (r, n, Paste_after) -> ( 546 | Shortcut (r, n, Paste_after) -> (
475 get_register ?r >>= function 547 get_register ?r >>= function
476 | Empty -> noop 548 | Empty -> noop
477 | Glyphwise z -> Buffer.Action.paste ?n z |> on_focused_buffer 549 | Glyphwise z ->
550 let* () = take_buffer_snapshot in
551 Buffer.Action.paste ?n z |> on_focused_buffer
478 | Linewise z -> 552 | Linewise z ->
553 let* () = take_buffer_snapshot in
479 Buffer.Action.paste ~linewise:true ?n z |> on_focused_buffer) 554 Buffer.Action.paste ~linewise:true ?n z |> on_focused_buffer)
480 | Shortcut (r, n, Paste_before) -> ( 555 | Shortcut (r, n, Paste_before) -> (
481 get_register ?r >>= function 556 get_register ?r >>= function
482 | Empty -> noop 557 | Empty -> noop
483 | Glyphwise z -> 558 | Glyphwise z ->
559 let* () = take_buffer_snapshot in
484 Buffer.Action.paste ~before:true ?n z |> on_focused_buffer 560 Buffer.Action.paste ~before:true ?n z |> on_focused_buffer
485 | Linewise z -> 561 | Linewise z ->
562 let* () = take_buffer_snapshot in
486 Buffer.Action.paste ~before:true ~linewise:true ?n z 563 Buffer.Action.paste ~before:true ~linewise:true ?n z
487 |> on_focused_buffer) 564 |> on_focused_buffer)
488 (* Join *) 565 (* Join *)
489 | Shortcut (_, n, Join) -> 566 | Shortcut (_, n, Join) ->
490 let n = Option.(value ~default:2 n) in 567 let n = Option.(value ~default:2 n) in
568 let* () = take_buffer_snapshot in
491 Buffer.Action.join_lines ~n |> on_focused_buffer 569 Buffer.Action.join_lines ~n |> on_focused_buffer
492 (* Control *) 570 (* Control *)
493 | Simple (Key ':' as k) -> 571 | Simple (Key ':' as k) ->
@@ -512,6 +590,12 @@ let handle_normal_command c =
512 | None -> set_message "No search history" 590 | None -> set_message "No search history"
513 | Some (dir, word) -> search (not dir) word |> repeat ?n) 591 | Some (dir, word) -> search (not dir) word |> repeat ?n)
514 | Simple (Ctrl 'Q') -> quit 0 592 | Simple (Ctrl 'Q') -> quit 0
593 (* History *)
594 | Shortcut (_, n, Undo) -> repeat ?n undo
595 | Shortcut (_, n, Redo) -> repeat ?n redo
596 | Shortcut (_, n, Earlier) -> repeat ?n timetravel
597 | Shortcut (_, n, Later) -> repeat ?n (timetravel ~later:true)
598 (* | Shortcut (_, n, Redo) -> repeat ?n redo *)
515 (* Misc *) 599 (* Misc *)
516 | Simple (Key 'A') -> 600 | Simple (Key 'A') ->
517 (Buffer.Action.eol |> on_focused_buffer) *> set_mode Insert 601 (Buffer.Action.eol |> on_focused_buffer) *> set_mode Insert
diff --git a/lib/editorBuffer.ml b/lib/editorBuffer.ml
index 959c04a..8aacd71 100644
--- a/lib/editorBuffer.ml
+++ b/lib/editorBuffer.ml
@@ -10,15 +10,17 @@ type buffer = {
10 kind : kind; 10 kind : kind;
11 content : (char zipper zipper, error) Result.t; 11 content : (char zipper zipper, error) Result.t;
12 rendered : char Sequence.t zipper; 12 rendered : char Sequence.t zipper;
13 last_modified : float;
13} 14}
14 15
15type t = buffer 16type t = buffer
16 17
17let empty = 18let empty () =
18 { 19 {
19 kind = No_name; 20 kind = No_name;
20 content = empty |> push empty |> Result.return; 21 content = empty |> push empty |> Result.return;
21 rendered = push Sequence.empty empty; 22 rendered = push Sequence.empty empty;
23 last_modified = Unix.gettimeofday ();
22 } 24 }
23 25
24let kind b = b.kind 26let kind b = b.kind
@@ -106,13 +108,14 @@ module Action = struct
106 match b.content with 108 match b.content with
107 | Error _ -> ((), b) 109 | Error _ -> ((), b)
108 | Ok c -> 110 | Ok c ->
109 let step = if before then left else right in 111 let rstep = if before then left else right ~by_one:false in
112 let cstep = if before then left else right ~by_one:false in
110 let rec aux i r c = 113 let rec aux i r c =
111 if i = 0 then r 114 if i = 0 then r
112 else 115 else
113 let default = Sequence.empty in 116 let default = Sequence.empty in
114 let l = apply_focus_or ~default (to_seq &> render) c in 117 let l = apply_focus_or ~default (to_seq &> render) c in
115 let c' = step c and r' = swap_focus l r |> step in 118 let c' = cstep c and r' = swap_focus l r |> rstep in
116 aux (i - 1) r' c' 119 aux (i - 1) r' c'
117 in 120 in
118 ((), { b with rendered = aux n b.rendered c |> goto (left_length c) }) 121 ((), { b with rendered = aux n b.rendered c |> goto (left_length c) })
@@ -444,9 +447,11 @@ let from_file f =
444 Sequence.(of_list lines |> map ~f:line_to_seq) 447 Sequence.(of_list lines |> map ~f:line_to_seq)
445 with Unix.Unix_error (ENOENT, _, _) -> Sequence.empty 448 with Unix.Unix_error (ENOENT, _, _) -> Sequence.empty
446 in 449 in
447 let rendered = Sequence.map ~f:render lines |> of_seq in 450 let kind = File f
448 let content = Sequence.map ~f:of_seq lines |> of_seq in 451 and content = Sequence.map ~f:of_seq lines |> of_seq |> Result.return
449 { kind = File f; content = Ok content; rendered } 452 and rendered = Sequence.map ~f:render lines |> of_seq
453 and last_modified = Unix.gettimeofday () in
454 { kind; content; rendered; last_modified }
450 455
451let unrendered_view x y h w b = 456let unrendered_view x y h w b =
452 match b.content with 457 match b.content with