summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <undyamon@disroot.org>2024-01-24 21:14:11 +0100
committerFederico Igne <undyamon@disroot.org>2024-01-24 21:14:11 +0100
commitaf0cd851fec5038faff5a8133cadad6c65568374 (patch)
tree5f594f6140f6e070fb4a96b1ba4d937d7f43d1b7
parent7510a0194125ad6229fe8e84f436faa7f87b7c25 (diff)
downloadsandy-af0cd851fec5038faff5a8133cadad6c65568374.tar.gz
sandy-af0cd851fec5038faff5a8133cadad6c65568374.zip
feat: add ability to paste text from a register
Register are simplier than Vim register, in particular no register is local to buffers.
-rw-r--r--lib/command.ml3
-rw-r--r--lib/editor.ml98
-rw-r--r--lib/editorBuffer.ml55
-rw-r--r--lib/zipper.ml12
-rw-r--r--lib/zipper.mli12
5 files changed, 117 insertions, 63 deletions
diff --git a/lib/command.ml b/lib/command.ml
index 74b616a..a55fb9e 100644
--- a/lib/command.ml
+++ b/lib/command.ml
@@ -93,7 +93,8 @@ let n_stream =
93 match (s, k) with 93 match (s, k) with
94 | `start, Key '"' -> (`chord_reg_pre, Partial k) 94 | `start, Key '"' -> (`chord_reg_pre, Partial k)
95 (* Register *) 95 (* Register *)
96 | `chord_reg_pre, Key c -> (`chord_reg c, Partial k) 96 | `chord_reg_pre, Key c when Char.('!' <= c && c <= '~') ->
97 (`chord_reg c, Partial k)
97 (* Count (first) *) 98 (* Count (first) *)
98 | `start, Key n when Char.('1' <= n && n <= '9') -> 99 | `start, Key n when Char.('1' <= n && n <= '9') ->
99 let n = Char.to_int n - 48 in 100 let n = Char.to_int n - 48 in
diff --git a/lib/editor.ml b/lib/editor.ml
index f8091b8..0ed2229 100644
--- a/lib/editor.ml
+++ b/lib/editor.ml
@@ -3,6 +3,12 @@ module Buffer = EditorBuffer
3open Util 3open Util
4 4
5type mode = Normal | Insert | Control 5type mode = Normal | Insert | Control
6
7type selection =
8 | Empty
9 | Glyphwise of char Sequence.t Sequence.t
10 | Linewise of char Sequence.t Sequence.t
11
6type cursor = int * int 12type cursor = int * int
7 13
8type editor = { 14type editor = {
@@ -19,6 +25,7 @@ type editor = {
19 message_timestamp : float; 25 message_timestamp : float;
20 message_duration : float; 26 message_duration : float;
21 pending_command : string; 27 pending_command : string;
28 registers : selection Array.t;
22} 29}
23 30
24type t = editor 31type t = editor
@@ -38,6 +45,7 @@ let init (c : Config.t) : editor =
38 message_timestamp = Unix.time (); 45 message_timestamp = Unix.time ();
39 message_duration = 5.; 46 message_duration = 5.;
40 pending_command = ""; 47 pending_command = "";
48 registers = Array.create ~len:128 Empty;
41 } 49 }
42 50
43let string_of_mode = function 51let string_of_mode = function
@@ -142,6 +150,16 @@ module Action = struct
142 let set_focused_buffer b e = ((), { e with buffer = Some b }) 150 let set_focused_buffer b e = ((), { e with buffer = Some b })
143 let get_terminal_size e = (e.term.size, e) 151 let get_terminal_size e = (e.term.size, e)
144 152
153 let get_register r e =
154 assert (Char.('!' <= r && r <= '~'));
155 (e.registers.(Char.to_int r), e)
156
157 let set_register r z e =
158 assert (Char.('!' <= r && r <= '~'));
159 e.registers.(Char.to_int '"') <- z;
160 e.registers.(Char.to_int r) <- z;
161 ((), e)
162
145 let on_focused_buffer f = 163 let on_focused_buffer f =
146 let f e = { e with buffer = Option.map ~f e.buffer } in 164 let f e = { e with buffer = Option.map ~f e.buffer } in
147 modify ~f *> update_cursor 165 modify ~f *> update_cursor
@@ -218,64 +236,6 @@ let move ?(up = 0) ?(down = 0) ?(left = 0) ?(right = 0) (x, y) =
218 236
219let move_to ?x ?y (sx, sy) = Option.(value x ~default:sx, value y ~default:sy) 237let move_to ?x ?y (sx, sy) = Option.(value x ~default:sx, value y ~default:sy)
220 238
221(* let get_next_command s = *)
222(* match Sequence.next s.pending with *)
223(* | None -> (None, s) *)
224(* | Some (h, t) -> (Some h, { s with pending = t }) *)
225
226(* let handle_insert_key = *)
227(* let open Action in *)
228(* let open Key in *)
229(* function *)
230(* | Arrow_down -> Buffer.Action.down |> on_focused_buffer *)
231(* | Arrow_left -> Buffer.Action.left |> on_focused_buffer *)
232(* | Arrow_right -> Buffer.Action.right |> on_focused_buffer *)
233(* | Arrow_up -> Buffer.Action.up |> on_focused_buffer *)
234(* | Backspace -> Buffer.Action.delete_before |> on_focused_buffer *)
235(* | Ctrl 'Q' -> quit 0 *)
236(* | Delete -> Buffer.Action.delete_after |> on_focused_buffer *)
237(* | Enter -> Buffer.Action.newline |> on_focused_buffer *)
238(* | Esc -> (Buffer.Action.left |> on_focused_buffer) *> set_mode Normal *)
239(* | Key k -> Buffer.Action.insert k |> on_focused_buffer *)
240(* | _ -> noop *)
241
242(* let handle_normal_key = *)
243(* let open Action in *)
244(* let open Key in *)
245(* function *)
246(* | Arrow_down | Key 'j' -> Buffer.Action.down |> on_focused_buffer *)
247(* | Arrow_left | Backspace | Key 'h' -> Buffer.Action.left |> on_focused_buffer *)
248(* | Arrow_right | Key ' ' | Key 'l' -> Buffer.Action.right |> on_focused_buffer *)
249(* | Arrow_up | Key 'k' -> Buffer.Action.up |> on_focused_buffer *)
250(* | Ctrl 'Q' -> quit 0 *)
251(* | Key '0' -> Buffer.Action.bol |> on_focused_buffer_or_new *)
252(* | Key 'A' -> *)
253(* (Buffer.Action.eol |> on_focused_buffer_or_new) *> set_mode Insert *)
254(* | Key 'a' -> *)
255(* (Buffer.Action.right |> on_focused_buffer_or_new) *> set_mode Insert *)
256(* | Key 'G' -> Buffer.Action.eof |> on_focused_buffer_or_new *)
257(* | Key 'I' -> *)
258(* noop *)
259(* (1* (Buffer.Action.bol |> on_focused_buffer_or_new) *> set_mode Insert *1) *)
260(* | Key 'i' -> (Fn.id |> on_focused_buffer_or_new) *> set_mode Insert *)
261(* | Key 's' -> *)
262(* (Buffer.Action.delete_after |> on_focused_buffer_or_new) *)
263(* *> set_mode Insert *)
264(* | Key 'x' -> Buffer.Action.delete_after |> on_focused_buffer_or_new *)
265(* | Key 'X' -> Buffer.Action.delete_before |> on_focused_buffer_or_new *)
266(* | Key '$' -> Buffer.Action.eol |> on_focused_buffer_or_new *)
267(* | _ -> noop *)
268
269(* let handle_next_command = *)
270(* let f m = function *)
271(* | None -> Action.return () *)
272(* | Some k -> ( *)
273(* match m with *)
274(* | Insert -> handle_insert_key k *)
275(* | Normal -> handle_normal_key k) *)
276(* in *)
277(* Action.(map2 ~f get_mode get_next_command |> join) *)
278
279let handle_insert_command = 239let handle_insert_command =
280 let open Command in 240 let open Command in
281 let open Action in 241 let open Action in
@@ -434,6 +394,28 @@ let handle_normal_command c =
434 Buffer.Action.( 394 Buffer.Action.(
435 delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) 395 delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol)
436 |> on_focused_buffer_or_new 396 |> on_focused_buffer_or_new
397 (* Paste *)
398 | Shortcut (r, n, Paste_after) ->
399 let r = Option.value ~default:'"' r in
400 let paste = function
401 | Empty -> noop
402 | Glyphwise z -> Buffer.Action.paste ?n z |> on_focused_buffer_or_new
403 | Linewise z ->
404 Buffer.Action.paste ~linewise:true ?n z
405 |> on_focused_buffer_or_new
406 in
407 get_register r >>= paste
408 | Shortcut (r, n, Paste_before) ->
409 let r = Option.value ~default:'"' r in
410 let paste = function
411 | Empty -> noop
412 | Glyphwise z ->
413 Buffer.Action.paste ~before:true ?n z |> on_focused_buffer_or_new
414 | Linewise z ->
415 Buffer.Action.paste ~before:true ~linewise:true ?n z
416 |> on_focused_buffer_or_new
417 in
418 get_register r >>= paste
437 (* Join *) 419 (* Join *)
438 | Shortcut (_, n, Join) -> 420 | Shortcut (_, n, Join) ->
439 let n = Option.(value ~default:1 n) in 421 let n = Option.(value ~default:1 n) in
diff --git a/lib/editorBuffer.ml b/lib/editorBuffer.ml
index c492b8b..295e6e7 100644
--- a/lib/editorBuffer.ml
+++ b/lib/editorBuffer.ml
@@ -61,12 +61,22 @@ module Action = struct
61 61
62 (* let on_content_stored ?(register = '"') ?(append = false) f b = ... *) 62 (* let on_content_stored ?(register = '"') ?(append = false) f b = ... *)
63 63
64 let update_render_at_cursor b = 64 let update_render ?(before = false) ~n b =
65 match b.content with 65 match b.content with
66 | Error _ -> b 66 | Error _ -> b
67 | Ok c -> 67 | Ok c ->
68 let l = apply_focus_or ~default:Sequence.empty (to_seq &> render) c in 68 let step = if before then left else right in
69 { b with rendered = swap_focus l b.rendered } 69 let rec aux i r c =
70 if i = 0 then r
71 else
72 let default = Sequence.empty in
73 let l = apply_focus_or ~default (to_seq &> render) c in
74 let c' = step c and r' = swap_focus l r |> step in
75 aux (i - 1) r' c'
76 in
77 { b with rendered = aux n b.rendered c |> goto (left_length c) }
78
79 let update_render_at_cursor = update_render ~n:1
70 80
71 let move_up ?(n = 1) = 81 let move_up ?(n = 1) =
72 let change_content = 82 let change_content =
@@ -218,6 +228,45 @@ module Action = struct
218 in 228 in
219 change_content &> change_rendered &> update_render_at_cursor 229 change_content &> change_rendered &> update_render_at_cursor
220 230
231 let paste ?(before = false) ?(linewise = false) ?(n = 1) s =
232 let change_content =
233 if linewise then
234 let push = if before then push_before_seq else push_after_seq in
235 push (Sequence.map ~f:of_seq s) |> on_content
236 else
237 let aux z =
238 match Sequence.next s with
239 | None -> z
240 | Some (h, t) ->
241 let init =
242 let default = Zipper.(of_seq h |> far_right) in
243 map_focus_or ~default (push_before_seq h) z
244 and f z l =
245 let default = (Zipper.empty, Zipper.empty) in
246 let z1, z2 = apply_focus_or ~default split z in
247 z |> push_before z1 |> swap_focus z2
248 |> map_focus (push_before_seq l)
249 in
250 let folded = Sequence.fold ~init ~f t in
251 if before then folded
252 else
253 folded
254 |> Fn.apply_n_times ~n:(Sequence.length t) left
255 |> map_focus (Fn.apply_n_times ~n:(Sequence.length h) left)
256 in
257 on_content aux
258 and change_rendered =
259 if linewise then
260 let push = if before then push_before_seq else push_after_seq in
261 push (Sequence.map ~f:render s) |> on_rendered
262 else
263 let len = Sequence.length s in
264 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
266 on_rendered aux &> update_render ~before ~n:len
267 in
268 Fn.apply_n_times ~n (change_content &> change_rendered)
269
221 (* let save_history_to ?(clear = true) r = () *) 270 (* let save_history_to ?(clear = true) r = () *)
222end 271end
223 272
diff --git a/lib/zipper.ml b/lib/zipper.ml
index 202f6d4..413f365 100644
--- a/lib/zipper.ml
+++ b/lib/zipper.ml
@@ -61,11 +61,21 @@ let pop_after ?(n = 1) z =
61 if right_length z < 2 then z else right z |> pop ~n |> left 61 if right_length z < 2 then z else right z |> pop ~n |> left
62 62
63let push x z = { z with after = Sequence.shift_right z.after x } 63let push x z = { z with after = Sequence.shift_right z.after x }
64let push_seq s z = { z with after = Sequence.append s z.after }
64let push_after x z = right z |> push x |> left 65let push_after x z = right z |> push x |> left
66let push_after_seq s z = right z |> push_seq s |> left
65 67
66let push_before x z = 68let push_before x z =
67 { z with pos = z.pos + 1; before = Sequence.shift_right z.before x } 69 { z with pos = z.pos + 1; before = Sequence.shift_right z.before x }
68 70
71let push_before_seq s z =
72 let f a e = Sequence.shift_right a e in
73 {
74 z with
75 pos = z.pos + Sequence.length s;
76 before = Sequence.fold ~init:z.before ~f s;
77 }
78
69let split z = 79let split z =
70 ( { z with after = Sequence.empty }, 80 ( { z with after = Sequence.empty },
71 { z with pos = 0; before = Sequence.empty } ) 81 { z with pos = 0; before = Sequence.empty } )
@@ -119,7 +129,7 @@ let filter p z = z |> filter_left p |> filter_right p
119let context_left n z = { z with before = Sequence.take z.before n } 129let context_left n z = { z with before = Sequence.take z.before n }
120let context_right n z = { z with after = Sequence.take z.after n } 130let context_right n z = { z with after = Sequence.take z.after n }
121let context ~l ?(r = l) z = z |> context_left l |> context_right r 131let context ~l ?(r = l) z = z |> context_left l |> context_right r
122let swap_focus a = map_focus (Fn.const a) 132let swap_focus a = map_focus_or ~default:a (Fn.const a)
123let of_seq s = { empty with after = s } 133let of_seq s = { empty with after = s }
124let to_seq z = z |> far_left |> after 134let to_seq z = z |> far_left |> after
125let window ~from ~len z = goto from z |> context_right len |> after 135let window ~from ~len z = goto from z |> context_right len |> after
diff --git a/lib/zipper.mli b/lib/zipper.mli
index d79604e..0bbdf27 100644
--- a/lib/zipper.mli
+++ b/lib/zipper.mli
@@ -136,17 +136,29 @@ val push : 'a -> 'a zipper -> 'a zipper
136 Calling [push 0 z], if [z] is [([3; 2; 1], [4; 5])], 136 Calling [push 0 z], if [z] is [([3; 2; 1], [4; 5])],
137 the result is [([3; 2; 1], [0; 4; 5]))], *) 137 the result is [([3; 2; 1], [0; 4; 5]))], *)
138 138
139val push_seq : 'a Sequence.t -> 'a zipper -> 'a zipper
140(** Like {!Zipper.push}, but inserts a sequence of elements at the cursor
141 position. *)
142
139val push_after : 'a -> 'a zipper -> 'a zipper 143val push_after : 'a -> 'a zipper -> 'a zipper
140(** Insert an element after the cursor. Behaves like {!Zipper.push} if 144(** Insert an element after the cursor. Behaves like {!Zipper.push} if
141 the cursor is at the far right of the zipper. 145 the cursor is at the far right of the zipper.
142 Calling [push_after 0 z], if [z] is [([3; 2; 1], [4; 5])], 146 Calling [push_after 0 z], if [z] is [([3; 2; 1], [4; 5])],
143 the result is [([3; 2; 1], [4; 0; 5]))], *) 147 the result is [([3; 2; 1], [4; 0; 5]))], *)
144 148
149val push_after_seq : 'a Sequence.t -> 'a zipper -> 'a zipper
150(** Like {!Zipper.push_after}, but inserts a sequence of elements after
151 the cursor. *)
152
145val push_before : 'a -> 'a zipper -> 'a zipper 153val push_before : 'a -> 'a zipper -> 'a zipper
146(** Insert an element before the cursor. Return the modified zipper. 154(** Insert an element before the cursor. Return the modified zipper.
147 Calling [push_before 0 z], if [z] is [([3; 2; 1], [4; 5])], 155 Calling [push_before 0 z], if [z] is [([3; 2; 1], [4; 5])],
148 the result is [([0; 3; 2; 1], [4; 5]))]. *) 156 the result is [([0; 3; 2; 1], [4; 5]))]. *)
149 157
158val push_before_seq : 'a Sequence.t -> 'a zipper -> 'a zipper
159(** Like {!Zipper.push_before}, but inserts a sequence of elements
160 before the cursor. *)
161
150val split : 'a zipper -> 'a zipper * 'a zipper 162val split : 'a zipper -> 'a zipper * 'a zipper
151(** [split z] splits the zipper in two. [([3; 2; 1], [4; 5])] becomes 163(** [split z] splits the zipper in two. [([3; 2; 1], [4; 5])] becomes
152 [([3; 2; 1], []), ([], [4; 5])]. *) 164 [([3; 2; 1], []), ([], [4; 5])]. *)