summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <undyamon@disroot.org>2024-01-22 23:44:14 +0100
committerFederico Igne <undyamon@disroot.org>2024-01-22 23:44:14 +0100
commit0b2c183dbf275fbca3f9e0522cc583f85edccab5 (patch)
tree32bcc85dbb28425792c66edf7890cba3ccd46f5b
parent43bf616d8e58adf393762b13663cbff5ffb84ce3 (diff)
downloadsandy-0b2c183dbf275fbca3f9e0522cc583f85edccab5.tar.gz
sandy-0b2c183dbf275fbca3f9e0522cc583f85edccab5.zip
refactor: naming convention in zipper
Unless specified otherwise: - "before" and "left" mean "before the cursor"; - "right" mean "after (and including) the cursor"; - "after" mean "after (i.e., excluding) the cursor".
-rw-r--r--lib/zipper.ml96
-rw-r--r--lib/zipper.mli125
2 files changed, 112 insertions, 109 deletions
diff --git a/lib/zipper.ml b/lib/zipper.ml
index 9313518..202f6d4 100644
--- a/lib/zipper.ml
+++ b/lib/zipper.ml
@@ -2,28 +2,14 @@
2 2
3open Base 3open Base
4 4
5type !+'a zipper = { 5type !+'a zipper = { pos : int; before : 'a Sequence.t; after : 'a Sequence.t }
6 pos : int;
7 popped : 'a Sequence.t;
8 before : 'a Sequence.t;
9 after : 'a Sequence.t;
10}
11
12type !+'a t = 'a zipper 6type !+'a t = 'a zipper
13 7
14let empty = 8let empty = { pos = 0; before = Sequence.empty; after = Sequence.empty }
15 {
16 pos = 0;
17 popped = Sequence.empty;
18 before = Sequence.empty;
19 after = Sequence.empty;
20 }
21
22let before z = z.before 9let before z = z.before
23let after z = z.after 10let after z = z.after
24let focus z = after z |> Sequence.next |> Option.map ~f:fst 11let focus z = after z |> Sequence.next |> Option.map ~f:fst
25let focus_or z ~default = Option.value ~default (focus z) 12let focus_or ~default z = Option.value ~default (focus z)
26let history z = z.popped
27let is_far_left z = before z |> Sequence.is_empty 13let is_far_left z = before z |> Sequence.is_empty
28let is_far_right z = after z |> Sequence.is_empty 14let is_far_right z = after z |> Sequence.is_empty
29let is_empty z = is_far_left z && is_far_right z 15let is_empty z = is_far_left z && is_far_right z
@@ -35,12 +21,7 @@ let left z =
35 match Sequence.next z.before with 21 match Sequence.next z.before with
36 | None -> z 22 | None -> z
37 | Some (h, t) -> 23 | Some (h, t) ->
38 { 24 { pos = z.pos - 1; before = t; after = Sequence.shift_right z.after h }
39 z with
40 pos = z.pos - 1;
41 before = t;
42 after = Sequence.shift_right z.after h;
43 }
44 25
45let rec left_while f z = 26let rec left_while f z =
46 if (not (is_far_left z)) && Option.(focus z |> map ~f |> value ~default:false) 27 if (not (is_far_left z)) && Option.(focus z |> map ~f |> value ~default:false)
@@ -53,12 +34,7 @@ let right z =
53 match Sequence.next z.after with 34 match Sequence.next z.after with
54 | None -> z 35 | None -> z
55 | Some (h, t) -> 36 | Some (h, t) ->
56 { 37 { pos = z.pos + 1; before = Sequence.shift_right z.before h; after = t }
57 z with
58 pos = z.pos + 1;
59 before = Sequence.shift_right z.before h;
60 after = t;
61 }
62 38
63let rec right_while f z = 39let rec right_while f z =
64 if 40 if
@@ -73,34 +49,46 @@ let goto n z =
73 let step = if n < 0 then left else right in 49 let step = if n < 0 then left else right in
74 Fn.apply_n_times ~n:(abs n) step z 50 Fn.apply_n_times ~n:(abs n) step z
75 51
76let pop_after z = { z with after = Sequence.drop_eagerly z.after 1 } 52let pop ?(n = 1) z = { z with after = Sequence.drop_eagerly z.after n }
77let pop_before z = if is_far_left z then z else z |> left |> pop_after 53
78let pop = pop_before 54let pop_before ?(n = 1) =
79let push_after x z = { z with after = Sequence.shift_right z.after x } 55 let rec aux m z =
56 if m < n && not (is_far_left z) then aux (m + 1) (left z) else pop ~n:m z
57 in
58 aux 0
59
60let pop_after ?(n = 1) z =
61 if right_length z < 2 then z else right z |> pop ~n |> left
62
63let push x z = { z with after = Sequence.shift_right z.after x }
64let push_after x z = right z |> push x |> left
80 65
81let push_before x z = 66let push_before x z =
82 { z with pos = z.pos + 1; before = Sequence.shift_right z.before x } 67 { z with pos = z.pos + 1; before = Sequence.shift_right z.before x }
83 68
84let push = push_before
85
86let split z = 69let split z =
87 ( { z with after = Sequence.empty }, 70 ( { z with after = Sequence.empty },
88 { z with pos = 0; before = Sequence.empty } ) 71 { z with pos = 0; before = Sequence.empty } )
89 72
90let join z1 z2 = { z1 with after = z2.after } 73let join z1 ~z2 =
91let iter_before f z = Sequence.iter ~f z.before 74 let z1 = far_right z1 and z2 = far_left z2 in
92let iter_after f z = Sequence.iter ~f z.after 75 { z1 with after = z2.after }
76
77let iter_left f z = Sequence.iter ~f z.before
78let iter_right f z = Sequence.iter ~f z.after
93 79
94let iter f z = 80let iter f z =
95 iter_before f z; 81 iter_left f z;
96 iter_after f z 82 iter_right f z
97 83
98let for_all f z = Sequence.(for_all ~f z.before && for_all ~f z.after) 84let for_all f z = Sequence.(for_all ~f z.before && for_all ~f z.after)
99let exists f z = Sequence.(exists ~f z.before || exists ~f z.after) 85let exists f z = Sequence.(exists ~f z.before || exists ~f z.after)
100let find_before f z = Sequence.find ~f z.before 86let find_left f z = Sequence.find ~f z.before
101let find_after f z = Sequence.find ~f z.after 87let find_right f z = Sequence.find ~f z.after
102let map_before f z = { z with before = Sequence.map ~f z.before } 88let apply_focus f z = Option.map ~f (focus z)
103let map_after f z = { z with after = Sequence.map ~f z.after } 89let apply_focus_or ~default f z = Option.value ~default (apply_focus f z)
90let map_left f z = { z with before = Sequence.map ~f z.before }
91let map_right f z = { z with after = Sequence.map ~f z.after }
104 92
105let map_focus f z = 93let map_focus f z =
106 match Sequence.next z.after with 94 match Sequence.next z.after with
@@ -115,8 +103,8 @@ let map_focus_or ~default f z =
115let map f z = 103let map f z =
116 { z with before = Sequence.map ~f z.before; after = Sequence.map ~f z.after } 104 { z with before = Sequence.map ~f z.before; after = Sequence.map ~f z.after }
117 105
118let mapi_before f z = { z with before = Sequence.mapi ~f z.before } 106let mapi_left f z = { z with before = Sequence.mapi ~f z.before }
119let mapi_after f z = { z with after = Sequence.mapi ~f z.after } 107let mapi_right f z = { z with after = Sequence.mapi ~f z.after }
120 108
121let mapi f z = 109let mapi f z =
122 { 110 {
@@ -125,13 +113,13 @@ let mapi f z =
125 after = Sequence.mapi ~f z.after; 113 after = Sequence.mapi ~f z.after;
126 } 114 }
127 115
128let filter_before f z = { z with before = Sequence.filter ~f z.before } 116let filter_left f z = { z with before = Sequence.filter ~f z.before }
129let filter_after f z = { z with after = Sequence.filter ~f z.after } 117let filter_right f z = { z with after = Sequence.filter ~f z.after }
130let filter p z = z |> filter_before p |> filter_after p 118let filter p z = z |> filter_left p |> filter_right p
131let context_before n z = { z with before = Sequence.take z.before n } 119let context_left n z = { z with before = Sequence.take z.before n }
132let context_after n z = { z with after = Sequence.take z.after n } 120let context_right n z = { z with after = Sequence.take z.after n }
133let context ~b ?(a = b) z = z |> context_before b |> context_after a 121let context ~l ?(r = l) z = z |> context_left l |> context_right r
134let clear_history z = { z with popped = Sequence.empty } 122let swap_focus a = map_focus (Fn.const a)
135let of_seq s = { empty with after = s } 123let of_seq s = { empty with after = s }
136let to_seq z = z |> far_left |> after 124let to_seq z = z |> far_left |> after
137let window ~from ~len z = goto from z |> context_after len |> after 125let window ~from ~len z = goto from z |> context_right len |> after
diff --git a/lib/zipper.mli b/lib/zipper.mli
index e25d57b..d79604e 100644
--- a/lib/zipper.mli
+++ b/lib/zipper.mli
@@ -35,17 +35,14 @@ val before : 'a zipper -> 'a Sequence.t
35(** Return the sequence before the cursor *) 35(** Return the sequence before the cursor *)
36 36
37val after : 'a zipper -> 'a Sequence.t 37val after : 'a zipper -> 'a Sequence.t
38(** Return the sequence after the cursor *) 38(** Return the sequence after (and including) the cursor *)
39 39
40val focus : 'a zipper -> 'a option 40val focus : 'a zipper -> 'a option
41(** Return the focus of the zipper, if any. *) 41(** Return the focus of the zipper, if any. *)
42 42
43val focus_or : 'a zipper -> default:'a -> 'a 43val focus_or : default:'a -> 'a zipper -> 'a
44(** Return the focus of the zipper, or a user-provided default, otherwise. *) 44(** Return the focus of the zipper, or a user-provided default, otherwise. *)
45 45
46val history : 'a zipper -> 'a Sequence.t
47(** Returns the sequence of elements [pop]ped so far from the zipper. *)
48
49val is_far_left : 'a zipper -> bool 46val is_far_left : 'a zipper -> bool
50(** Return whether the cursor is at the beginning of the zipper. *) 47(** Return whether the cursor is at the beginning of the zipper. *)
51 48
@@ -109,43 +106,52 @@ val goto : int -> 'a zipper -> 'a zipper
109 This involve [push]ing and [pop]ping elements before and after the 106 This involve [push]ing and [pop]ping elements before and after the
110 cursor. *) 107 cursor. *)
111 108
112val pop_after : 'a zipper -> 'a zipper 109val pop : ?n:int -> 'a zipper -> 'a zipper
113(** Remove the element at the cursor position, if any, and return the 110(** Remove [n] elements at the cursor position (1 by default), if any,
114 modified zipper. Calling [pop_after z], 111 and return the modified zipper. Calling [pop z],
115 112
116 - if [z] is [([3; 2; 1], [4; 5])], the result is [([3; 2; 1], [5])], 113 - if [z] is [([3; 2; 1], [4; 5])], the result is [([3; 2; 1], [5])],
117 - if [z] is [([1; 2; 3], [])], the result is [([1; 2; 3], [])]. 114 - if [z] is [([1; 2; 3], [])], the result is [([1; 2; 3], [])].
118 *) 115 *)
119 116
120val pop_before : 'a zipper -> 'a zipper 117val pop_before : ?n:int -> 'a zipper -> 'a zipper
121(** Remove the element before the cursor, if any, and return the 118(** Remove [n] elements before the cursor (1 by default), if any, and
122 modified zipper. Calling [pop_before z], 119 return the modified zipper. Calling [pop_before z],
123 120
124 - if [z] is [([3; 2; 1], [4; 5])], the result is [([2; 1], [4, 5])], 121 - if [z] is [([3; 2; 1], [4; 5])], the result is [([2; 1], [4, 5])],
125 - if [z] is [([], [1; 2; 3])], the result is [([], [1; 2; 3])]. 122 - if [z] is [([], [1; 2; 3])], the result is [([], [1; 2; 3])].
126 *) 123 *)
127 124
128val pop : 'a zipper -> 'a zipper 125val pop_after : ?n:int -> 'a zipper -> 'a zipper
129(** [pop] is an alias for [pop_before]. *) 126(** Remove [n] elements after (and {b not} including) the cursor
127 (1 by default), if any, and return the modified zipper.
128 Calling [pop_after z],
129
130 - if [z] is [([3; 2; 1], [4; 5])], the result is [([3; 2; 1], [4])],
131 - if [z] is [([1; 2; 3], [4])], the result is [([1; 2; 3], [4])].
132 *)
133
134val push : 'a -> 'a zipper -> 'a zipper
135(** Insert an element at the cursor position.
136 Calling [push 0 z], if [z] is [([3; 2; 1], [4; 5])],
137 the result is [([3; 2; 1], [0; 4; 5]))], *)
130 138
131val push_after : 'a -> 'a zipper -> 'a zipper 139val push_after : 'a -> 'a zipper -> 'a zipper
132(** Insert an element after the cursor. 140(** Insert an element after the cursor. Behaves like {!Zipper.push} if
141 the cursor is at the far right of the zipper.
133 Calling [push_after 0 z], if [z] is [([3; 2; 1], [4; 5])], 142 Calling [push_after 0 z], if [z] is [([3; 2; 1], [4; 5])],
134 the result is [([3; 2; 1], [0; 4, 5]))], *) 143 the result is [([3; 2; 1], [4; 0; 5]))], *)
135 144
136val push_before : 'a -> 'a zipper -> 'a zipper 145val push_before : 'a -> 'a zipper -> 'a zipper
137(** Insert an element before the cursor. Return the modified zipper. 146(** Insert an element before the cursor. Return the modified zipper.
138 Calling [push_before 0 z], if [z] is [([3; 2; 1], [4; 5])], 147 Calling [push_before 0 z], if [z] is [([3; 2; 1], [4; 5])],
139 the result is [([0; 3; 2; 1], [4, 5]))]. *) 148 the result is [([0; 3; 2; 1], [4; 5]))]. *)
140
141val push : 'a -> 'a zipper -> 'a zipper
142(** [push] is an alias for [push_before]. *)
143 149
144val split : 'a zipper -> 'a zipper * 'a zipper 150val split : 'a zipper -> 'a zipper * 'a zipper
145(** [split z] splits the zipper in two. [([3; 2; 1], [4; 5])] becomes 151(** [split z] splits the zipper in two. [([3; 2; 1], [4; 5])] becomes
146 [([3; 2; 1], []), ([], [4; 5])]. *) 152 [([3; 2; 1], []), ([], [4; 5])]. *)
147 153
148val join : 'a zipper -> 'a zipper -> 'a zipper 154val join : 'a zipper -> z2:'a zipper -> 'a zipper
149(** [join z1 z2] creates a new zipper using [before z1] and [after z2]. 155(** [join z1 z2] creates a new zipper using [before z1] and [after z2].
150 [([3; 2; 1], []) ([4; 2], [4; 5])] becomes [([3; 2; 1], [4; 5])]. *) 156 [([3; 2; 1], []) ([4; 2], [4; 5])] becomes [([3; 2; 1], [4; 5])]. *)
151 157
@@ -156,16 +162,16 @@ val join : 'a zipper -> 'a zipper -> 'a zipper
156 Unless otherwise stated, these functions will iterate on the 162 Unless otherwise stated, these functions will iterate on the
157 elements before the cursor, first. *) 163 elements before the cursor, first. *)
158 164
159val iter_before : ('a -> unit) -> 'a zipper -> unit 165val iter_left : ('a -> unit) -> 'a zipper -> unit
160(** [iter_before f z] will call [f x] for all [x], elements before the 166(** [iter_left f z] will call [f x] for all [x], elements before the
161 cursor in [z].*) 167 cursor in [z].*)
162 168
163val iter_after : ('a -> unit) -> 'a zipper -> unit 169val iter_right : ('a -> unit) -> 'a zipper -> unit
164(** [iter_after f z] will call [f x] for all [x], elements after the 170(** [iter_right f z] will call [f x] for all [x], elements after (in
165 cursor in [z].*) 171 including) the cursor in [z]. *)
166 172
167val iter : ('a -> unit) -> 'a zipper -> unit 173val iter : ('a -> unit) -> 'a zipper -> unit
168(** [iter f z] is equivalent to [iter_before f z; iter_after f z] *) 174(** [iter f z] is equivalent to [iter_left f z; iter_right f z] *)
169 175
170val for_all : ('a -> bool) -> 'a zipper -> bool 176val for_all : ('a -> bool) -> 'a zipper -> bool
171(** [for_all p z] tests whether a predicate [p] is [true] for all 177(** [for_all p z] tests whether a predicate [p] is [true] for all
@@ -175,25 +181,33 @@ val exists : ('a -> bool) -> 'a zipper -> bool
175(** [exists p z] tests whether at least one element in the zipper is 181(** [exists p z] tests whether at least one element in the zipper is
176 [true] according to the predicate [p]. *) 182 [true] according to the predicate [p]. *)
177 183
178val find_before : ('a -> bool) -> 'a zipper -> 'a option 184val find_left : ('a -> bool) -> 'a zipper -> 'a option
179(** [find_before p z] will return the first element before the cursor in 185(** [find_left p z] will return the first element before the cursor in
180 [z] satisfying the predicate [p], if any. *) 186 [z] satisfying the predicate [p], if any. *)
181 187
182val find_after : ('a -> bool) -> 'a zipper -> 'a option 188val find_right : ('a -> bool) -> 'a zipper -> 'a option
183(** [find_after p z] will return the first element after the cursor in 189(** [find_right p z] will return the first element after the cursor in
184 [z] satisfying the predicate [p], if any. *) 190 [z] satisfying the predicate [p], if any. *)
185 191
192val apply_focus : ('a -> 'b) -> 'a zipper -> 'b option
193(** [apply focus f z] applies f to the current focus, if any, and
194 returns its result *)
195
196val apply_focus_or : default:'b -> ('a -> 'b) -> 'a zipper -> 'b
197(** [apply focus f z] applies f to the current focus and returns its
198 result. Return a default value if no element is in focus. *)
199
186(** {1 Transforming zippers} *) 200(** {1 Transforming zippers} *)
187 201
188(** Since zippers are based on sequences, the functions in this section 202(** Since zippers are based on sequences, the functions in this section
189 are lazy; i.e., resulting elements of the zipper are computed only 203 are lazy; i.e., resulting elements of the zipper are computed only
190 when demanded. *) 204 when demanded. *)
191 205
192val map_before : ('a -> 'a) -> 'a zipper -> 'a zipper 206val map_left : ('a -> 'a) -> 'a zipper -> 'a zipper
193(** Map a function over all elements before the cursor. *) 207(** Map a function over all elements before the cursor. *)
194 208
195val map_after : ('a -> 'a) -> 'a zipper -> 'a zipper 209val map_right : ('a -> 'a) -> 'a zipper -> 'a zipper
196(** Map a function over all elements after the cursor. *) 210(** Map a function over all elements after (and including) the cursor. *)
197 211
198val map_focus : ('a -> 'a) -> 'a zipper -> 'a zipper 212val map_focus : ('a -> 'a) -> 'a zipper -> 'a zipper
199(** Map a function over the element focused by the cursor, if any. *) 213(** Map a function over the element focused by the cursor, if any. *)
@@ -202,31 +216,31 @@ val map_focus_or : default:'a -> ('a -> 'a) -> 'a zipper -> 'a zipper
202(** Map a function over the element focused by the cursor. Push 216(** Map a function over the element focused by the cursor. Push
203 [default] if no element is focused. *) 217 [default] if no element is focused. *)
204 218
205val map : ('a -> 'a) -> 'a zipper -> 'a zipper 219val map : ('a -> 'b) -> 'a zipper -> 'b zipper
206(** Map a function over all elements of a zipper. *) 220(** Map a function over all elements of a zipper. *)
207 221
208val mapi_before : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper 222val mapi_left : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper
209(** [mapi_before] is analogous to {!Zipper.map_before}, but the function 223(** [mapi_left] is analogous to {!Zipper.map_left}, but the function
210 takes an index and an element. 224 takes an index and an element.
211 The index indicates the distance of an element from the cursor. *) 225 The index indicates the distance of an element from the cursor. *)
212 226
213val mapi_after : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper 227val mapi_right : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper
214(** [mapi_after] is analogous to {!Zipper.map_after}, but the function 228(** [mapi_right] is analogous to {!Zipper.map_right}, but the function
215 takes an index and an element. 229 takes an index and an element.
216 The index indicates the distance of an element from the cursor. *) 230 The index indicates the distance of an element from the cursor. *)
217 231
218val mapi : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper 232val mapi : (int -> 'a -> 'b) -> 'a zipper -> 'b zipper
219(** [mapi] is analogous to {!Zipper.map}, but the function takes an 233(** [mapi] is analogous to {!Zipper.map}, but the function takes an
220 index and an element. 234 index and an element.
221 The index indicates the distance of an element from the cursor. *) 235 The index indicates the distance of an element from the cursor. *)
222 236
223val filter_before : ('a -> bool) -> 'a zipper -> 'a zipper 237val filter_left : ('a -> bool) -> 'a zipper -> 'a zipper
224(** [filter_before p z] filters the elements before the cursor in a 238(** [filter_left p z] filters the elements before the cursor in a
225 zipper [z] according to a predicate [p], i.e., keeping the elements 239 zipper [z] according to a predicate [p], i.e., keeping the elements
226 that satisfy the predicate. *) 240 that satisfy the predicate. *)
227 241
228val filter_after : ('a -> bool) -> 'a zipper -> 'a zipper 242val filter_right : ('a -> bool) -> 'a zipper -> 'a zipper
229(** [filter_after p z] filters the elements after the cursor in a 243(** [filter_right p z] filters the elements after the cursor in a
230 zipper [z] according to a predicate [p], i.e., keeping the elements 244 zipper [z] according to a predicate [p], i.e., keeping the elements
231 that satisfy the predicate. *) 245 that satisfy the predicate. *)
232 246
@@ -235,21 +249,22 @@ val filter : ('a -> bool) -> 'a zipper -> 'a zipper
235 predicate [p], i.e., keeping the elements that satisfy the 249 predicate [p], i.e., keeping the elements that satisfy the
236 predicate. *) 250 predicate. *)
237 251
238val context_before : int -> 'a zipper -> 'a zipper 252val context_left : int -> 'a zipper -> 'a zipper
239(** [context_before n z] will limit the zipper [z] to [n] elements before 253(** [context_left n z] will limit the zipper [z] to [n] elements before
240 the cursor. *) 254 the cursor. *)
241 255
242val context_after : int -> 'a zipper -> 'a zipper 256val context_right : int -> 'a zipper -> 'a zipper
243(** [context_after n z] will limit the zipper [z] to [n] elements after 257(** [context_right n z] will limit the zipper [z] to [n] elements after
244 the cursor. *) 258 the cursor. *)
245 259
246val context : b:int -> ?a:int -> 'a zipper -> 'a zipper 260val context : l:int -> ?r:int -> 'a zipper -> 'a zipper
247(** [context ~b ~a z] will limit the zipper [z] to [b] elements before 261(** [context ~l ~r z] will limit the zipper [z] to [l] elements before
248 the cursor and [a] elements after the cursor. When [a] is not 262 the cursor and [r] elements after the cursor. When [r] is not
249 provided, it defaults to [b]. *) 263 provided, it defaults to [l]. *)
250 264
251val clear_history : 'a zipper -> 'a zipper 265val swap_focus : 'a -> 'a zipper -> 'a zipper
252(** Clear the history of the zipper. See {!Zipper.history}. *) 266(** Swap the element in focus with a newly provided element. Nothing
267 happens if no element is in focus. *)
253 268
254(** {1 Zippers and sequences} *) 269(** {1 Zippers and sequences} *)
255 270