summaryrefslogtreecommitdiff
path: root/lib/editor.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/editor.ml')
-rw-r--r--lib/editor.ml106
1 files changed, 95 insertions, 11 deletions
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