summaryrefslogtreecommitdiff
path: root/lib/editor.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/editor.ml')
-rw-r--r--lib/editor.ml137
1 files changed, 120 insertions, 17 deletions
diff --git a/lib/editor.ml b/lib/editor.ml
index 043c00e..5a68e53 100644
--- a/lib/editor.ml
+++ b/lib/editor.ml
@@ -2,8 +2,6 @@ open Base
2module Buffer = EditorBuffer 2module Buffer = EditorBuffer
3open Util 3open Util
4 4
5type mode = Normal | Insert | Control
6
7type selection = 5type selection =
8 | Empty 6 | Empty
9 | Glyphwise of char Sequence.t Sequence.t 7 | Glyphwise of char Sequence.t Sequence.t
@@ -13,7 +11,7 @@ type cursor = int * int
13 11
14type editor = { 12type editor = {
15 term : Terminal.state; 13 term : Terminal.state;
16 mode : mode; 14 mode : Mode.t;
17 offset : int * int; 15 offset : int * int;
18 cursor : cursor; 16 cursor : cursor;
19 buffer : Buffer.t; 17 buffer : Buffer.t;
@@ -26,6 +24,8 @@ type editor = {
26 message_duration : float; 24 message_duration : float;
27 pending_command : string; 25 pending_command : string;
28 registers : selection Array.t; 26 registers : selection Array.t;
27 control : Control.t;
28 search_history : (bool * char Sequence.t) Zipper.t;
29} 29}
30 30
31type t = editor 31type t = editor
@@ -49,19 +49,16 @@ let init (c : Config.t) : editor =
49 message_duration = 5.; 49 message_duration = 5.;
50 pending_command = ""; 50 pending_command = "";
51 registers = Array.create ~len:128 Empty; 51 registers = Array.create ~len:128 Empty;
52 control = Control.create Key.Nul;
53 search_history = Zipper.empty;
52 } 54 }
53 55
54let string_of_mode = function
55 | Insert -> " I "
56 | Normal -> " N "
57 | Control -> " C "
58
59let statusbar e = 56let statusbar e =
60 let open Text in 57 let open Text in
61 (* let open Sequence.Infix in *) 58 (* let open Sequence.Infix in *)
62 let w = e.term.size |> snd in 59 let w = e.term.size |> snd in
63 let status = 60 let status =
64 let mode = e.mode |> string_of_mode |> sequence_of_string in 61 let mode = e.mode |> Mode.to_string |> sequence_of_string in
65 let lsize = Sequence.length mode 62 let lsize = Sequence.length mode
66 and c = e.buffer.kind |> Buffer.string_of_kind |> sequence_of_string 63 and c = e.buffer.kind |> Buffer.string_of_kind |> sequence_of_string
67 and br, bc = Buffer.size e.buffer 64 and br, bc = Buffer.size e.buffer
@@ -79,9 +76,12 @@ let statusbar e =
79 let rsize = Sequence.length nav in 76 let rsize = Sequence.length nav in
80 spread ~l:(bold mode) ~lsize ~c ~r:(bold nav) ~rsize ~fill:' ' w |> invert 77 spread ~l:(bold mode) ~lsize ~c ~r:(bold nav) ~rsize ~fill:' ' w |> invert
81 and control = 78 and control =
82 let msg = Option.value ~default:"" e.message |> sequence_of_string 79 match e.mode with
83 and cmd = e.pending_command |> sequence_of_string in 80 | Control -> Control.render e.control
84 spread ~l:msg ~r:cmd ~fill:' ' w 81 | _ ->
82 let msg = Option.value ~default:"" e.message |> sequence_of_string
83 and cmd = e.pending_command |> sequence_of_string in
84 spread ~l:msg ~r:cmd ~fill:' ' w
85 in 85 in
86 Sequence.(take (of_list [ status; control ]) e.status_size) 86 Sequence.(take (of_list [ status; control ]) e.status_size)
87 87
@@ -117,8 +117,16 @@ module Action = struct
117 let map = `Define_using_bind 117 let map = `Define_using_bind
118 end) 118 end)
119 119
120 let ( let+ ) e f = map e ~f
120 let ( let* ) e f = bind e ~f 121 let ( let* ) e f = bind e ~f
121 let ( and* ) = both 122 let ( and* ) = both
123
124 let rec repeat ?(n = 1) a =
125 match n with
126 | _ when n <= 0 -> return ()
127 | 1 -> a
128 | _ -> a *> repeat ~n:(n - 1) a
129
122 let get e = (e, e) 130 let get e = (e, e)
123 let put e _ = ((), e) 131 let put e _ = ((), e)
124 let modify ~f e = ((), f e) 132 let modify ~f e = ((), f e)
@@ -149,8 +157,22 @@ module Action = struct
149 let* b = get_focused_buffer in 157 let* b = get_focused_buffer in
150 return (f b |> fst) 158 return (f b |> fst)
151 159
160 let get_control_buffer e = (e.control, e)
161 let set_control_buffer c e = ((), { e with control = c })
162
163 let on_control_buffer f =
164 let* c = get_control_buffer in
165 set_control_buffer (f c)
166
152 let get_mode e = (e.mode, e) 167 let get_mode e = (e.mode, e)
153 let set_mode m e = ((), { e with mode = m }) 168 let set_mode m e = ((), { e with mode = m })
169 let get_search_history e = (e.search_history, e)
170 let set_search_history h e = ((), { e with search_history = h })
171 let on_search_history f = get_search_history >>| f >>= set_search_history
172
173 let set_last_search dir word =
174 Zipper.(far_left &> swap_focus (dir, word)) |> on_search_history
175
154 let get_terminal_size e = (e.term.size, e) 176 let get_terminal_size e = (e.term.size, e)
155 177
156 let get_register ?(r = '"') e = 178 let get_register ?(r = '"') e =
@@ -179,8 +201,14 @@ module Action = struct
179 |> Text.extend ~fill r 201 |> Text.extend ~fill r
180 |> Fn.flip Sequence.take (r - ssize) 202 |> Fn.flip Sequence.take (r - ssize)
181 in 203 in
182 let screen = Sequence.append bufview status in 204 let screen = Sequence.append bufview status
183 Terminal.redraw screen e.cursor 205 and cursor =
206 let open Mode in
207 match e.mode with
208 | Control -> (r, Control.cursor e.control)
209 | _ -> e.cursor
210 in
211 Terminal.redraw screen cursor
184 in 212 in
185 get >>| aux 213 get >>| aux
186 214
@@ -189,7 +217,7 @@ module Action = struct
189 217
190 (* Statusbar *) 218 (* Statusbar *)
191 let set_message m e = 219 let set_message m e =
192 ((), { e with message = m; message_timestamp = Unix.time () }) 220 ((), { e with message = Some m; message_timestamp = Unix.time () })
193 221
194 let get_pending_command e = (e.pending_command, e) 222 let get_pending_command e = (e.pending_command, e)
195 let set_pending_command p e = ((), { e with pending_command = p }) 223 let set_pending_command p e = ((), { e with pending_command = p })
@@ -209,6 +237,15 @@ module Action = struct
209 in 237 in
210 get >>| check_message_timestamp >>= put 238 get >>| check_message_timestamp >>= put
211 239
240 (* Control line *)
241 let search dir word =
242 let* coords = Buffer.Action.(search dir word |> on_focused_buffer) in
243 match coords with
244 | None ->
245 let word = word |> Sequence.to_list |> String.of_list in
246 set_message (Printf.sprintf "Pattern not found: %s" word)
247 | Some (r, c) -> Buffer.Action.goto r c |> on_focused_buffer
248
212 (* Debug *) 249 (* Debug *)
213 let get_rendered e = (e.rendered, e) 250 let get_rendered e = (e.rendered, e)
214 let set_rendered r e = ((), { e with rendered = r }) 251 let set_rendered r e = ((), { e with rendered = r })
@@ -448,7 +485,28 @@ let handle_normal_command c =
448 | Shortcut (_, n, Join) -> 485 | Shortcut (_, n, Join) ->
449 let n = Option.(value ~default:2 n) in 486 let n = Option.(value ~default:2 n) in
450 Buffer.Action.join_lines ~n |> on_focused_buffer 487 Buffer.Action.join_lines ~n |> on_focused_buffer
451 (* Quit *) 488 (* Control *)
489 | Simple (Key ':' as k) ->
490 let c = Control.create k in
491 set_control_buffer c *> set_mode Control
492 | Simple (Key '/' as k) ->
493 let c = Control.create k in
494 (Zipper.(far_left &> push (true, Sequence.empty)) |> on_search_history)
495 *> set_control_buffer c *> set_mode Control
496 | Simple (Key '?' as k) ->
497 let c = Control.create k in
498 (Zipper.(far_left &> push (false, Sequence.empty)) |> on_search_history)
499 *> set_control_buffer c *> set_mode Control
500 | Shortcut (_, n, Search) -> (
501 let* h = get_search_history in
502 match Zipper.focus h with
503 | None -> set_message "No search history"
504 | Some (dir, word) -> search dir word |> repeat ?n)
505 | Shortcut (_, n, Search_rev) -> (
506 let* h = get_search_history in
507 match Zipper.focus h with
508 | None -> set_message "No search history"
509 | Some (dir, word) -> search (not dir) word |> repeat ?n)
452 | Simple (Ctrl 'Q') -> quit 0 510 | Simple (Ctrl 'Q') -> quit 0
453 (* Misc *) 511 (* Misc *)
454 | Simple (Key 'A') -> 512 | Simple (Key 'A') ->
@@ -467,7 +525,49 @@ let handle_normal_command c =
467 in 525 in
468 compute_action *> update_command_cue 526 compute_action *> update_command_cue
469 527
528let handle_control_command =
529 let open Command in
530 let open Action in
531 function
532 | Simple Arrow_down ->
533 let* c = get_control_buffer in
534 if Control.is_search c then
535 let* () = Zipper.left |> on_search_history
536 and* h = get_search_history in
537 match Zipper.focus h with
538 | None -> noop
539 | Some (_, word) -> Control.set_content word |> on_control_buffer
540 else failwith "Control line command history unimplemented!"
541 | Simple Arrow_left -> Control.move_left |> on_control_buffer
542 | Simple Arrow_right -> Control.move_right |> on_control_buffer
543 | Simple Arrow_up ->
544 let* c = get_control_buffer in
545 if Control.is_search c then
546 let* () = Zipper.right |> on_search_history
547 and* h = get_search_history in
548 match Zipper.focus h with
549 | None -> noop
550 | Some (_, word) -> Control.set_content word |> on_control_buffer
551 else failwith "Control line command history unimplemented!"
552 | Simple Backspace -> Control.delete_before |> on_control_buffer
553 | Simple Delete -> Control.delete_after |> on_control_buffer
554 | Simple Enter -> (
555 let* () = set_mode Normal and* c = get_control_buffer in
556 match Control.get_result c with
557 | Search (dir, word) -> search dir word *> set_last_search dir word
558 | No_result -> noop)
559 | Simple Esc -> (
560 let* () = set_mode Normal and* c = get_control_buffer in
561 match Control.get_result c with
562 | Search _ -> Zipper.(far_left &> pop &> snd) |> on_search_history
563 | No_result -> noop)
564 | Simple Home -> Control.bol |> on_control_buffer
565 | Simple End -> Control.eol |> on_control_buffer
566 | Type k -> Control.insert k |> on_control_buffer
567 | _ -> noop
568
470let handle_next_command m e = 569let handle_next_command m e =
570 let open Mode in
471 match m with 571 match m with
472 | Insert -> ( 572 | Insert -> (
473 match Sequence.next e.istream with 573 match Sequence.next e.istream with
@@ -477,7 +577,10 @@ let handle_next_command m e =
477 match Sequence.next e.nstream with 577 match Sequence.next e.nstream with
478 | None -> ((), e) 578 | None -> ((), e)
479 | Some (h, t) -> handle_normal_command h { e with nstream = t }) 579 | Some (h, t) -> handle_normal_command h { e with nstream = t })
480 | Control -> failwith "unimplemented" 580 | Control -> (
581 match Sequence.next e.istream with
582 | None -> ((), e)
583 | Some (h, t) -> handle_control_command h { e with istream = t })
481 584
482let handle_next_command = 585let handle_next_command =
483 let open Action in 586 let open Action in