From 055c743c55bde27f4475d3434c26d8383c0c3ea1 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Thu, 11 Jan 2024 19:31:31 +0100 Subject: bulk: add PoC of vim-like modular editor --- lib/editorBuffer.ml | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 lib/editorBuffer.ml (limited to 'lib/editorBuffer.ml') diff --git a/lib/editorBuffer.ml b/lib/editorBuffer.ml new file mode 100644 index 0000000..5104549 --- /dev/null +++ b/lib/editorBuffer.ml @@ -0,0 +1,72 @@ +open Base +open Zipper +open Util + +type kind = File of string | No_name | Scratch +type error = No_such_file | Other +type buffer = { kind : kind; content : (char zipper zipper, error) Result.t } +type t = buffer + +let empty = + { kind = No_name; content = empty |> push_after empty |> Result.return } + +module Action = struct + let on_content f b = { b with content = Result.map ~f b.content } + + let up, down, left, right = + let vertical f ?(n = 1) = + on_content (fun z -> + let col = focus_or ~default:Zipper.empty z |> left_length in + Fn.apply_n_times ~n f z |> map_focus (goto col)) + and horizontal f ?(n = 1) = + Fn.apply_n_times ~n (map_focus f) |> on_content + in + (vertical left, vertical right, horizontal left, horizontal right) + + let bol = map_focus far_left |> on_content + let eol = map_focus far_right |> on_content + let bof = far_left |> on_content + let eof = far_right |> on_content + let insert k = map_focus (push k) |> on_content + let delete_after ~n = Fn.apply_n_times ~n (map_focus pop_after) |> on_content + let delete_before ~n = Fn.apply_n_times ~n (map_focus pop) |> on_content + let delete_to_eol = map_focus (split &> fst) |> on_content + let delete_to_bol = map_focus (split &> snd) |> on_content + let delete_lines ~n = Fn.apply_n_times ~n pop_after |> on_content + + let delete_lines_before ~n = + on_content (fun z -> pop_after z |> Fn.apply_n_times ~n:(n - 1) pop_before) + + let newline = + let aux z = + let l1, l2 = focus_or ~default:Zipper.empty z |> split in + push_before l1 z |> map_focus (Fn.const l2) + in + on_content aux + + (* let save_history_to ?(clear = true) r = () *) +end + +let from_file f = + let lines = Stdio.In_channel.read_lines f in + let line_to_zipper l = String.to_list l |> Sequence.of_list |> of_seq in + let content = Sequence.(of_list lines |> map ~f:line_to_zipper) |> of_seq in + { kind = File f; content = Ok content } + +let cursor b = + let open Option in + let x = Result.(map ~f:left_length b.content |> ok |> value ~default:0) + and y = + Result.(map ~f:focus b.content |> ok) + |> join |> map ~f:left_length |> value ~default:0 + in + (x, y) + +let view x y h w b = + match b.content with + | Error _ -> Sequence.empty + | Ok z -> + let cx, _ = cursor b in + context ~b:(cx - x) ~a:(x + h - cx) z + |> to_seq + |> Sequence.map ~f:(window ~from:y ~len:w) -- cgit v1.2.3