diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/editorBuffer.ml | 271 |
1 files changed, 189 insertions, 82 deletions
diff --git a/lib/editorBuffer.ml b/lib/editorBuffer.ml index 295e6e7..52b1115 100644 --- a/lib/editorBuffer.ml +++ b/lib/editorBuffer.ml | |||
| @@ -55,15 +55,54 @@ let cursor ?(rendered = true) b = | |||
| 55 | in | 55 | in |
| 56 | (left_length c, apply_focus_or ~default:0 hlen c) | 56 | (left_length c, apply_focus_or ~default:0 hlen c) |
| 57 | 57 | ||
| 58 | type 'a action = t -> 'a * t | ||
| 59 | |||
| 58 | module Action = struct | 60 | module Action = struct |
| 59 | let on_content f b = { b with content = Result.map ~f b.content } | 61 | include Applicative.Make (struct |
| 60 | let on_rendered f b = { b with rendered = f b.rendered } | 62 | type 'a t = 'a action |
| 63 | |||
| 64 | let return a b = (a, b) | ||
| 65 | |||
| 66 | let apply f a b = | ||
| 67 | let g, b = f b in | ||
| 68 | let x, b = a b in | ||
| 69 | (g x, b) | ||
| 70 | |||
| 71 | let map = `Define_using_apply | ||
| 72 | end) | ||
| 73 | |||
| 74 | include Monad.Make (struct | ||
| 75 | type 'a t = 'a action | ||
| 76 | |||
| 77 | let return x b = (x, b) | ||
| 78 | |||
| 79 | let bind a ~f x = | ||
| 80 | let y, a' = a x in | ||
| 81 | f y a' | ||
| 82 | |||
| 83 | let map = `Define_using_bind | ||
| 84 | end) | ||
| 85 | |||
| 86 | let ( let* ) b f = bind b ~f | ||
| 87 | let ( and* ) = both | ||
| 88 | let ( let+ ) b f = map b ~f | ||
| 89 | let get b = (b, b) | ||
| 90 | let put b _ = ((), b) | ||
| 91 | let modify ~f = get >>= (put &> f) | ||
| 92 | let on_content f b = ((), { b with content = Result.map ~f b.content }) | ||
| 93 | |||
| 94 | let on_content_with_output ~default f b = | ||
| 95 | match b.content with | ||
| 96 | | Error _ -> (default, b) | ||
| 97 | | Ok z -> | ||
| 98 | let a, z = f z in | ||
| 99 | (a, { b with content = Ok z }) | ||
| 61 | 100 | ||
| 62 | (* let on_content_stored ?(register = '"') ?(append = false) f b = ... *) | 101 | let on_rendered f b = ((), { b with rendered = f b.rendered }) |
| 63 | 102 | ||
| 64 | let update_render ?(before = false) ~n b = | 103 | let update_render ?(before = false) ~n b = |
| 65 | match b.content with | 104 | match b.content with |
| 66 | | Error _ -> b | 105 | | Error _ -> ((), b) |
| 67 | | Ok c -> | 106 | | Ok c -> |
| 68 | let step = if before then left else right in | 107 | let step = if before then left else right in |
| 69 | let rec aux i r c = | 108 | let rec aux i r c = |
| @@ -74,51 +113,66 @@ module Action = struct | |||
| 74 | let c' = step c and r' = swap_focus l r |> step in | 113 | let c' = step c and r' = swap_focus l r |> step in |
| 75 | aux (i - 1) r' c' | 114 | aux (i - 1) r' c' |
| 76 | in | 115 | in |
| 77 | { b with rendered = aux n b.rendered c |> goto (left_length c) } | 116 | ((), { b with rendered = aux n b.rendered c |> goto (left_length c) }) |
| 78 | 117 | ||
| 79 | let update_render_at_cursor = update_render ~n:1 | 118 | let update_render_at_cursor = update_render ~before:false ~n:1 |
| 80 | 119 | ||
| 81 | let move_up ?(n = 1) = | 120 | let move_up ?(n = 1) = |
| 82 | let change_content = | 121 | let change_content = |
| 83 | on_content (fun z -> | 122 | let act z = |
| 84 | let col = apply_focus_or ~default:0 left_length z in | 123 | let col = apply_focus_or ~default:0 left_length z in |
| 85 | Fn.apply_n_times ~n left z |> map_focus (goto col)) | 124 | Fn.apply_n_times ~n left z |> map_focus (goto col) |
| 125 | in | ||
| 126 | on_content act | ||
| 86 | and change_rendered = on_rendered (Fn.apply_n_times ~n left) in | 127 | and change_rendered = on_rendered (Fn.apply_n_times ~n left) in |
| 87 | change_content &> change_rendered | 128 | change_content *> change_rendered |
| 88 | 129 | ||
| 89 | let move_down ?(n = 1) = | 130 | let move_down ?(n = 1) = |
| 90 | let change_content = | 131 | let change_content = |
| 91 | on_content (fun z -> | 132 | let act z = |
| 92 | let col = apply_focus_or ~default:0 left_length z in | 133 | let col = apply_focus_or ~default:0 left_length z in |
| 93 | Fn.apply_n_times ~n right z |> map_focus (goto col)) | 134 | Fn.apply_n_times ~n right z |> map_focus (goto col) |
| 135 | in | ||
| 136 | on_content act | ||
| 94 | and change_rendered = on_rendered (Fn.apply_n_times ~n right) in | 137 | and change_rendered = on_rendered (Fn.apply_n_times ~n right) in |
| 95 | change_content &> change_rendered | 138 | change_content *> change_rendered |
| 96 | 139 | ||
| 97 | let move_left, move_right = | 140 | let move_left, move_right = |
| 98 | let horizontal f ?(n = 1) = | 141 | let horizontal f ?(n = 1) = |
| 99 | let change_content = map_focus (Fn.apply_n_times ~n f) |> on_content in | 142 | map_focus (Fn.apply_n_times ~n f) |> on_content |
| 100 | change_content &> update_render_at_cursor | ||
| 101 | in | 143 | in |
| 102 | (horizontal left, horizontal right) | 144 | (horizontal left, horizontal right) |
| 103 | 145 | ||
| 104 | let bol = map_focus far_left |> on_content | 146 | let bol ?(n = 0) = move_down ~n *> (map_focus far_left |> on_content) |
| 105 | let eol = map_focus far_right |> on_content | 147 | let eol ?(n = 0) = move_down ~n *> (map_focus far_right |> on_content) |
| 106 | 148 | ||
| 107 | let bof = | 149 | let bof = |
| 108 | let change_content = far_left |> on_content | 150 | let change_content = far_left |> on_content |
| 109 | and change_rendered = far_left |> on_rendered in | 151 | and change_rendered = far_left |> on_rendered in |
| 110 | change_content &> change_rendered | 152 | change_content *> change_rendered |
| 111 | 153 | ||
| 112 | let eof = | 154 | let eof = |
| 113 | let change_content = far_right |> on_content | 155 | let change_content = far_right |> on_content |
| 114 | and change_rendered = far_right |> on_rendered in | 156 | and change_rendered = far_right |> on_rendered in |
| 115 | change_content &> change_rendered | 157 | change_content *> change_rendered |
| 116 | 158 | ||
| 117 | let insert k = | 159 | let insert k = |
| 118 | let change_content = map_focus (push_before k) |> on_content in | 160 | let change_content = map_focus (push_before k) |> on_content in |
| 119 | change_content &> update_render_at_cursor | 161 | change_content *> update_render_at_cursor |
| 120 | 162 | ||
| 121 | (* let replace k = () *) | 163 | let replace k = |
| 164 | let change_content = map_focus (swap_focus k) |> on_content in | ||
| 165 | change_content *> update_render_at_cursor | ||
| 166 | |||
| 167 | let insert_line ?(before = false) = | ||
| 168 | let change_content = | ||
| 169 | let push = if before then push_before else push_after in | ||
| 170 | push Zipper.empty |> on_content | ||
| 171 | and change_rendered = | ||
| 172 | let push = if before then push_before else push_after in | ||
| 173 | push Sequence.empty |> on_rendered | ||
| 174 | in | ||
| 175 | change_content *> change_rendered | ||
| 122 | 176 | ||
| 123 | let join_lines ?(n = 2) = | 177 | let join_lines ?(n = 2) = |
| 124 | let change_content = | 178 | let change_content = |
| @@ -126,14 +180,14 @@ module Action = struct | |||
| 126 | if right_length z < 2 then z | 180 | if right_length z < 2 then z |
| 127 | else | 181 | else |
| 128 | let to_join = right z |> focus_or ~default:Zipper.empty in | 182 | let to_join = right z |> focus_or ~default:Zipper.empty in |
| 129 | map_focus (join ~z2:to_join) z |> pop_after | 183 | map_focus (Zipper.join ~z2:to_join) z |> pop_after |> snd |
| 130 | in | 184 | in |
| 131 | Fn.apply_n_times ~n:(n - 1) join_2_lines |> on_content | 185 | Fn.apply_n_times ~n:(n - 1) join_2_lines |> on_content |
| 132 | and change_rendered = pop_after ~n:(n - 1) |> on_rendered in | 186 | and change_rendered = pop_after ~n:(n - 1) &> snd |> on_rendered in |
| 133 | change_content &> change_rendered &> update_render_at_cursor | 187 | change_content *> change_rendered *> update_render_at_cursor |
| 134 | 188 | ||
| 135 | let delete_after ?(cross_lines = false) ~n b = | 189 | let delete_after ?(cross_lines = false) ~n = |
| 136 | let lines_to_delete = | 190 | let lines_to_delete b = |
| 137 | match b.content with | 191 | match b.content with |
| 138 | | Error _ -> 0 | 192 | | Error _ -> 0 |
| 139 | | Ok z -> ( | 193 | | Ok z -> ( |
| @@ -149,23 +203,38 @@ module Action = struct | |||
| 149 | |> Sequence.findi ~f:(fun _ a -> n <= a) | 203 | |> Sequence.findi ~f:(fun _ a -> n <= a) |
| 150 | |> Option.map ~f:fst | 204 | |> Option.map ~f:fst |
| 151 | |> Option.value ~default:(Sequence.length t)) | 205 | |> Option.value ~default:(Sequence.length t)) |
| 206 | and change_content = | ||
| 207 | let default = Sequence.empty in | ||
| 208 | on_content_with_output ~default (fun z -> | ||
| 209 | let rec aux i acc z = | ||
| 210 | let line = focus_or ~default:Zipper.empty z in | ||
| 211 | if right_length line >= i || (not cross_lines) || right_length z < 2 | ||
| 212 | then | ||
| 213 | let s, z1 = pop ~n:i line in | ||
| 214 | (s :: acc, swap_focus z1 z) | ||
| 215 | else | ||
| 216 | let rlen = right_length line in | ||
| 217 | let s, z1 = pop ~n:rlen line in | ||
| 218 | let z = swap_focus z1 z in | ||
| 219 | let to_join = right z |> focus_or ~default:Zipper.empty in | ||
| 220 | let z = | ||
| 221 | map_focus (Zipper.join ~z2:to_join) z |> pop_after |> snd | ||
| 222 | in | ||
| 223 | aux (i - rlen - 1) (s :: acc) z | ||
| 224 | in | ||
| 225 | let acc, z = aux n [] z in | ||
| 226 | (List.rev acc |> Sequence.of_list, z)) | ||
| 227 | and change_rendered n = | ||
| 228 | if cross_lines then pop_after ~n &> snd |> on_rendered else return () | ||
| 152 | in | 229 | in |
| 153 | let change_content = | 230 | let* n = get >>| lines_to_delete in |
| 154 | let delete_1_after z = | 231 | let* out = change_content |
| 155 | let line = focus_or ~default:Zipper.empty z in | 232 | and* () = change_rendered n |
| 156 | if cross_lines && is_far_right line && not (is_far_right z) then | 233 | and* () = update_render_at_cursor in |
| 157 | let to_join = right z |> focus_or ~default:Zipper.empty in | 234 | return out |
| 158 | map_focus (join ~z2:to_join) z |> pop_after | 235 | |
| 159 | else map_focus pop z | 236 | let delete_before ?(cross_lines = false) ~n = |
| 160 | in | 237 | let lines_to_delete b = |
| 161 | Fn.apply_n_times ~n delete_1_after |> on_content | ||
| 162 | and change_rendered = | ||
| 163 | if cross_lines then pop_after ~n:lines_to_delete |> on_rendered else Fn.id | ||
| 164 | in | ||
| 165 | b |> change_content |> change_rendered |> update_render_at_cursor | ||
| 166 | |||
| 167 | let delete_before ?(cross_lines = false) ~n b = | ||
| 168 | let lines_to_delete = | ||
| 169 | match b.content with | 238 | match b.content with |
| 170 | | Error _ -> 0 | 239 | | Error _ -> 0 |
| 171 | | Ok z -> | 240 | | Ok z -> |
| @@ -178,55 +247,87 @@ module Action = struct | |||
| 178 | |> Sequence.findi ~f:(fun _ a -> n <= a) | 247 | |> Sequence.findi ~f:(fun _ a -> n <= a) |
| 179 | |> Option.map ~f:fst | 248 | |> Option.map ~f:fst |
| 180 | |> Option.value ~default:(left_length z) | 249 | |> Option.value ~default:(left_length z) |
| 250 | and change_content = | ||
| 251 | let default = Sequence.empty in | ||
| 252 | on_content_with_output ~default (fun z -> | ||
| 253 | let rec aux i acc z = | ||
| 254 | let line = focus_or ~default:Zipper.empty z in | ||
| 255 | if left_length line >= i || (not cross_lines) || is_far_left z then | ||
| 256 | let s, z1 = pop_before ~n:i line in | ||
| 257 | let z' = swap_focus z1 z in | ||
| 258 | (s :: acc, z') | ||
| 259 | else | ||
| 260 | let llen = left_length line in | ||
| 261 | let s, z1 = pop_before ~n:llen line in | ||
| 262 | let z' = swap_focus z1 z in | ||
| 263 | let to_join = focus_or ~default:Zipper.empty z' in | ||
| 264 | let z'' = | ||
| 265 | left z' | ||
| 266 | |> map_focus (Zipper.join ~z2:to_join) | ||
| 267 | |> pop_after |> snd | ||
| 268 | in | ||
| 269 | aux (i - llen - 1) (s :: acc) z'' | ||
| 270 | in | ||
| 271 | let acc, z' = aux n [] z in | ||
| 272 | (List.rev acc |> Sequence.of_list, z')) | ||
| 273 | and change_rendered n = | ||
| 274 | if cross_lines then pop_before ~n &> snd |> on_rendered else return () | ||
| 181 | in | 275 | in |
| 182 | let change_content = | 276 | let* n = get >>| lines_to_delete in |
| 183 | let delete_1_before z = | 277 | let* out = change_content |
| 184 | let line = focus_or ~default:Zipper.empty z in | 278 | and* () = change_rendered n |
| 185 | if cross_lines && is_far_left line && not (is_far_left z) then | 279 | and* () = update_render_at_cursor in |
| 186 | left z |> map_focus (join ~z2:line) |> pop_after | 280 | return out |
| 187 | else map_focus pop_before z | ||
| 188 | in | ||
| 189 | Fn.apply_n_times ~n delete_1_before |> on_content | ||
| 190 | and change_rendered = | ||
| 191 | if cross_lines then pop_before ~n:lines_to_delete |> on_rendered | ||
| 192 | else Fn.id | ||
| 193 | in | ||
| 194 | b |> change_content |> change_rendered |> update_render_at_cursor | ||
| 195 | |||
| 196 | let delete_to_eol = | ||
| 197 | map_focus (split &> fst) |> on_content &> update_render_at_cursor | ||
| 198 | |||
| 199 | let delete_to_bol = | ||
| 200 | map_focus (split &> snd) |> on_content &> update_render_at_cursor | ||
| 201 | 281 | ||
| 202 | let delete_lines ~n = | 282 | let delete_lines ~n = |
| 203 | let change_content = pop ~n |> on_content | 283 | let default = Sequence.empty in |
| 204 | and change_rendered = pop ~n |> on_rendered in | 284 | let* out = pop ~n |> on_content_with_output ~default |
| 205 | change_content &> change_rendered | 285 | and* () = pop ~n &> snd |> on_rendered in |
| 286 | return (Sequence.map ~f:to_seq out) | ||
| 287 | |||
| 288 | (* TODO: maybe not needed *) | ||
| 289 | (* let delete_lines_before ~n b = *) | ||
| 290 | (* let default = Sequence.empty in *) | ||
| 291 | (* let out, b = on_content_with_output ~default (pop_before ~n) b in *) | ||
| 292 | (* (Sequence.map ~f:to_seq out, on_rendered (pop_before ~n &> snd) b) *) | ||
| 293 | |||
| 294 | let delete_to_eol ?(n = 0) = | ||
| 295 | let act z = | ||
| 296 | let default = (Zipper.empty, Zipper.empty) in | ||
| 297 | let z1, z2 = apply_focus_or ~default split z in | ||
| 298 | (to_seq z2, swap_focus z1 z) | ||
| 299 | in | ||
| 300 | let default = Sequence.empty in | ||
| 301 | let* h = act |> on_content_with_output ~default | ||
| 302 | and* t = move_down *> delete_lines ~n | ||
| 303 | and* () = move_up *> eol | ||
| 304 | and* () = update_render_at_cursor in | ||
| 305 | return (Sequence.shift_right t h) | ||
| 206 | 306 | ||
| 207 | let delete_lines_before ~n = | 307 | let delete_to_bol = |
| 208 | let change_content = pop_before ~n |> on_content | 308 | let act z = |
| 209 | and change_rendered = pop_before ~n |> on_rendered in | 309 | let default = (Zipper.empty, Zipper.empty) in |
| 210 | change_content &> change_rendered | 310 | let z1, z2 = apply_focus_or ~default split z in |
| 311 | (Sequence.singleton (to_seq z1), swap_focus z2 z) | ||
| 312 | in | ||
| 313 | let default = Sequence.empty in | ||
| 314 | let* out = act |> on_content_with_output ~default | ||
| 315 | and* () = update_render_at_cursor in | ||
| 316 | return out | ||
| 211 | 317 | ||
| 212 | let newline = | 318 | let newline = |
| 213 | let change_content = | 319 | let change_content = |
| 214 | let aux z = | 320 | let aux z = |
| 215 | let default = (Zipper.empty, Zipper.empty) in | 321 | let default = (Zipper.empty, Zipper.empty) in |
| 216 | let l1, l2 = apply_focus_or ~default split z in | 322 | let z1, z2 = apply_focus_or ~default split z in |
| 217 | push_before l1 z |> swap_focus l2 | 323 | push_before z1 z |> swap_focus z2 |
| 218 | in | 324 | in |
| 219 | on_content aux | 325 | on_content aux |
| 220 | and change_rendered b = | 326 | and change_rendered = |
| 221 | match b.content with | 327 | (push_before Sequence.empty |> on_rendered) |
| 222 | | Error _ -> b | 328 | *> update_render ~before:true ~n:2 |
| 223 | | Ok c -> ( | ||
| 224 | match Sequence.next (before c) with | ||
| 225 | | None -> failwith "newline > change_rendered: unreachable" | ||
| 226 | | Some (h, _) -> | ||
| 227 | { b with rendered = push_before (to_seq h |> render) b.rendered }) | ||
| 228 | in | 329 | in |
| 229 | change_content &> change_rendered &> update_render_at_cursor | 330 | change_content *> change_rendered |
| 230 | 331 | ||
| 231 | let paste ?(before = false) ?(linewise = false) ?(n = 1) s = | 332 | let paste ?(before = false) ?(linewise = false) ?(n = 1) s = |
| 232 | let change_content = | 333 | let change_content = |
| @@ -263,9 +364,15 @@ module Action = struct | |||
| 263 | let len = Sequence.length s in | 364 | let len = Sequence.length s in |
| 264 | let push = if before then push_before else push in | 365 | let push = if before then push_before else push in |
| 265 | let aux z = Fn.apply_n_times ~n:(len - 1) (push Sequence.empty) z in | 366 | let aux z = Fn.apply_n_times ~n:(len - 1) (push Sequence.empty) z in |
| 266 | on_rendered aux &> update_render ~before ~n:len | 367 | on_rendered aux *> update_render ~before ~n:len |
| 368 | in | ||
| 369 | let rec bind_n_times ~n act = | ||
| 370 | match n with | ||
| 371 | | _ when n <= 0 -> return () | ||
| 372 | | 1 -> act | ||
| 373 | | _ -> act *> bind_n_times ~n:(n - 1) act | ||
| 267 | in | 374 | in |
| 268 | Fn.apply_n_times ~n (change_content &> change_rendered) | 375 | bind_n_times ~n (change_content *> change_rendered) |
| 269 | 376 | ||
| 270 | (* let save_history_to ?(clear = true) r = () *) | 377 | (* let save_history_to ?(clear = true) r = () *) |
| 271 | end | 378 | end |
