From 53916fc3f7dcbefd90e3d0340a2a8f32bf331d1d Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Sun, 28 Jan 2024 01:22:52 +0100 Subject: feat: add plain search functionality (with history) --- lib/editorBuffer.ml | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'lib/editorBuffer.ml') diff --git a/lib/editorBuffer.ml b/lib/editorBuffer.ml index 52b1115..1f363ef 100644 --- a/lib/editorBuffer.ml +++ b/lib/editorBuffer.ml @@ -88,8 +88,10 @@ module Action = struct let ( let+ ) b f = map b ~f let get b = (b, b) let put b _ = ((), b) - let modify ~f = get >>= (put &> f) - let on_content f b = ((), { b with content = Result.map ~f b.content }) + let modify ~f = get >>| f >>= put + let get_content b = (b.content, b) + let set_content c b = ((), { b with content = c }) + let on_content f = get_content >>| Result.map ~f >>= set_content let on_content_with_output ~default f b = match b.content with @@ -143,6 +145,11 @@ module Action = struct in (horizontal left, horizontal right) + let goto r c = + let change_content = Zipper.(goto r &> map_focus (goto c)) |> on_content + and change_rendered = Zipper.goto r |> on_rendered in + change_content *> change_rendered + let bol ?(n = 0) = move_down ~n *> (map_focus far_left |> on_content) let eol ?(n = 0) = move_down ~n *> (map_focus far_right |> on_content) @@ -374,6 +381,55 @@ module Action = struct in bind_n_times ~n (change_content *> change_rendered) + let search forward word = + let rec tails s = + match Sequence.next s with + | None -> Sequence.empty + | Some (_, t) -> Sequence.shift_right (tails t) s + and prefix p l = + match Sequence.(next p, next l) with + | Some (ph, pt), Some (lh, lt) when Char.(ph = lh) -> prefix pt lt + | None, _ -> true + | _ -> false + in + let search_line w l = + Sequence.findi ~f:(fun _ -> prefix w) (tails l) |> Option.map ~f:fst + in + let* b = get in + let cr, cc = cursor ~rendered:false b in + let* c = get_content in + match c with + | Error _ -> return None + | Ok c -> ( + if forward then + match Sequence.next (Zipper.after c) with + | None -> return None + | Some (h, t) -> ( + match Zipper.(h |> right |> after) |> search_line word with + | Some i -> return (Some (cr, cc + i + 1)) + | None -> + let f r z = + z |> to_seq |> search_line word + |> Option.map ~f:(fun c -> (cr + r + 1, c)) + in + return (Sequence.find_mapi t ~f)) + else + let word = Sequence.(word |> to_list_rev |> of_list) in + let wlen = Sequence.length word in + match Zipper.(c |> right |> before) |> Sequence.next with + | None -> return None + | Some (h, t) -> ( + match h |> Zipper.before |> search_line word with + | Some i -> return (Some (cr, cc - wlen - i)) + | None -> + let f r z = + let z = z |> far_right in + let len = left_length z in + z |> before |> search_line word + |> Option.map ~f:(fun c -> (cr - r - 1, len - wlen - c)) + in + return (Sequence.find_mapi t ~f))) + (* let save_history_to ?(clear = true) r = () *) end -- cgit v1.2.3