diff options
| author | Federico Igne <undyamon@disroot.org> | 2024-01-28 23:40:30 +0100 |
|---|---|---|
| committer | Federico Igne <undyamon@disroot.org> | 2024-01-28 23:40:30 +0100 |
| commit | 05e1cc51b2fb0824580925b55319377305105c44 (patch) | |
| tree | f1bdc53ba8e312e764e7aa0765e1a6c72dd1c318 /lib/zipper.ml | |
| parent | f46d6661a8f33730c17cceb7e2885e789d6123d8 (diff) | |
| download | sandy-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.ml | 24 |
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 | ||
| 3 | open Base | 3 | open Base |
| 4 | 4 | ||
| @@ -11,7 +11,10 @@ let after z = z.after | |||
| 11 | let focus z = after z |> Sequence.next |> Option.map ~f:fst | 11 | let focus z = after z |> Sequence.next |> Option.map ~f:fst |
| 12 | let focus_or ~default z = Option.value ~default (focus z) | 12 | let focus_or ~default z = Option.value ~default (focus z) |
| 13 | let is_far_left z = before z |> Sequence.is_empty | 13 | let is_far_left z = before z |> Sequence.is_empty |
| 14 | let is_far_right z = after z |> Sequence.is_empty | 14 | |
| 15 | let is_far_right ?(by_one = false) z = | ||
| 16 | after z |> Sequence.length_is_bounded_by ~max:(if by_one then 1 else 0) | ||
| 17 | |||
| 15 | let is_empty z = is_far_left z && is_far_right z | 18 | let is_empty z = is_far_left z && is_far_right z |
| 16 | let left_length z = z.pos | 19 | let left_length z = z.pos |
| 17 | let right_length z = after z |> Sequence.length | 20 | let right_length z = after z |> Sequence.length |
| @@ -30,23 +33,26 @@ let rec left_while f z = | |||
| 30 | 33 | ||
| 31 | let rec far_left z = if is_far_left z then z else z |> left |> far_left | 34 | let rec far_left z = if is_far_left z then z else z |> left |> far_left |
| 32 | 35 | ||
| 33 | let right z = | 36 | let 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 | ||
| 39 | let rec right_while f z = | 43 | let 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 | ||
| 45 | let rec far_right z = if is_far_right z then z else z |> right |> far_right | 50 | let 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 | ||
| 47 | let goto n z = | 53 | let 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 | ||
| 52 | let pop ?(n = 1) z = | 58 | let pop ?(n = 1) z = |
