summaryrefslogtreecommitdiff
path: root/lib/zipper.ml
diff options
context:
space:
mode:
authorFederico Igne <undyamon@disroot.org>2024-01-28 23:40:30 +0100
committerFederico Igne <undyamon@disroot.org>2024-01-28 23:40:30 +0100
commit05e1cc51b2fb0824580925b55319377305105c44 (patch)
treef1bdc53ba8e312e764e7aa0765e1a6c72dd1c318 /lib/zipper.ml
parentf46d6661a8f33730c17cceb7e2885e789d6123d8 (diff)
downloadsandy-05e1cc51b2fb0824580925b55319377305105c44.tar.gz
sandy-05e1cc51b2fb0824580925b55319377305105c44.zip
feat(zipper): add option to not move past last element when moving right
Diffstat (limited to 'lib/zipper.ml')
-rw-r--r--lib/zipper.ml24
1 files changed, 15 insertions, 9 deletions
diff --git a/lib/zipper.ml b/lib/zipper.ml
index 5f3b37a..6077f21 100644
--- a/lib/zipper.ml
+++ b/lib/zipper.ml
@@ -1,4 +1,4 @@
1(* Module [Zipper]: functional zippers *) 1(* Module [Zipper]: functional linear zippers *)
2 2
3open Base 3open Base
4 4
@@ -11,7 +11,10 @@ let after z = z.after
11let focus z = after z |> Sequence.next |> Option.map ~f:fst 11let focus z = after z |> Sequence.next |> Option.map ~f:fst
12let focus_or ~default z = Option.value ~default (focus z) 12let focus_or ~default z = Option.value ~default (focus z)
13let is_far_left z = before z |> Sequence.is_empty 13let is_far_left z = before z |> Sequence.is_empty
14let is_far_right z = after z |> Sequence.is_empty 14
15let is_far_right ?(by_one = false) z =
16 after z |> Sequence.length_is_bounded_by ~max:(if by_one then 1 else 0)
17
15let is_empty z = is_far_left z && is_far_right z 18let is_empty z = is_far_left z && is_far_right z
16let left_length z = z.pos 19let left_length z = z.pos
17let right_length z = after z |> Sequence.length 20let right_length z = after z |> Sequence.length
@@ -30,23 +33,26 @@ let rec left_while f z =
30 33
31let rec far_left z = if is_far_left z then z else z |> left |> far_left 34let rec far_left z = if is_far_left z then z else z |> left |> far_left
32 35
33let right z = 36let right ?(by_one = false) z =
34 match Sequence.next z.after with 37 match Sequence.next z.after with
35 | None -> z 38 | None -> z
39 | Some (_, t) when by_one && Sequence.is_empty t -> z
36 | Some (h, t) -> 40 | Some (h, t) ->
37 { pos = z.pos + 1; before = Sequence.shift_right z.before h; after = t } 41 { pos = z.pos + 1; before = Sequence.shift_right z.before h; after = t }
38 42
39let rec right_while f z = 43let rec right_while ?(by_one = false) f z =
40 if 44 if
41 (not (is_far_right z)) && Option.(focus z |> map ~f |> value ~default:false) 45 (not (is_far_right ~by_one z))
42 then right z |> right_while f 46 && Option.(focus z |> map ~f |> value ~default:false)
47 then right z |> right_while ~by_one f
43 else z 48 else z
44 49
45let rec far_right z = if is_far_right z then z else z |> right |> far_right 50let rec far_right ?(by_one = false) z =
51 if is_far_right ~by_one z then z else z |> right |> far_right ~by_one
46 52
47let goto n z = 53let goto ?(by_one = false) n z =
48 let n = n - z.pos in 54 let n = n - z.pos in
49 let step = if n < 0 then left else right in 55 let step = if n < 0 then left else right ~by_one in
50 Fn.apply_n_times ~n:(abs n) step z 56 Fn.apply_n_times ~n:(abs n) step z
51 57
52let pop ?(n = 1) z = 58let pop ?(n = 1) z =