diff options
| -rw-r--r-- | lib/command.ml | 47 | ||||
| -rw-r--r-- | lib/editor.ml | 306 | ||||
| -rw-r--r-- | lib/key.ml | 19 | ||||
| -rw-r--r-- | lib/text.ml | 9 |
4 files changed, 213 insertions, 168 deletions
diff --git a/lib/command.ml b/lib/command.ml index 31e2ca2..74b616a 100644 --- a/lib/command.ml +++ b/lib/command.ml | |||
| @@ -18,6 +18,7 @@ type operation = | |||
| 18 | type scope = Line | To_bol | To_eol | Down | Left | Right | Up | 18 | type scope = Line | To_bol | To_eol | Down | Left | Right | Up |
| 19 | 19 | ||
| 20 | type command = | 20 | type command = |
| 21 | | Reset | ||
| 21 | | Type of char | 22 | | Type of char |
| 22 | | Simple of Key.t | 23 | | Simple of Key.t |
| 23 | | Partial of Key.t | 24 | | Partial of Key.t |
| @@ -89,59 +90,57 @@ let is_instant_operation k = List.mem ~equal:Poly.equal instant_operation k | |||
| 89 | 90 | ||
| 90 | let n_stream = | 91 | let n_stream = |
| 91 | let step s k = | 92 | let step s k = |
| 92 | let open Sequence.Step in | ||
| 93 | match (s, k) with | 93 | match (s, k) with |
| 94 | | `start, Key '"' -> Yield { value = Partial k; state = `chord_reg_pre } | 94 | | `start, Key '"' -> (`chord_reg_pre, Partial k) |
| 95 | (* Register *) | 95 | (* Register *) |
| 96 | | `chord_reg_pre, Key c -> Yield { value = Partial k; state = `chord_reg c } | 96 | | `chord_reg_pre, Key c -> (`chord_reg c, Partial k) |
| 97 | (* Count (first) *) | 97 | (* Count (first) *) |
| 98 | | `start, Key n when Char.('1' <= n && n <= '9') -> | 98 | | `start, Key n when Char.('1' <= n && n <= '9') -> |
| 99 | let n = Char.to_int n - 48 in | 99 | let n = Char.to_int n - 48 in |
| 100 | Yield { value = Partial k; state = `chord_fst_n (None, n) } | 100 | (`chord_fst_n (None, n), Partial k) |
| 101 | | `chord_reg r, Key n when Char.('1' <= n && n <= '9') -> | 101 | | `chord_reg r, Key n when Char.('1' <= n && n <= '9') -> |
| 102 | let n = Char.to_int n - 48 in | 102 | let n = Char.to_int n - 48 in |
| 103 | Yield { value = Partial k; state = `chord_fst_n (Some r, n) } | 103 | (`chord_fst_n (Some r, n), Partial k) |
| 104 | | `chord_fst_n (r, m), Key n when Char.('0' <= n && n <= '9') -> | 104 | | `chord_fst_n (r, m), Key n when Char.('0' <= n && n <= '9') -> |
| 105 | let n = (10 * m) + Char.to_int n - 48 in | 105 | let n = (10 * m) + Char.to_int n - 48 in |
| 106 | Yield { value = Partial k; state = `chord_fst_n (r, n) } | 106 | (`chord_fst_n (r, n), Partial k) |
| 107 | (* Instant operations *) | 107 | (* Instant operations *) |
| 108 | | `start, k when is_instant_operation k -> | 108 | | `start, k when is_instant_operation k -> (`start, shortcut (to_op k)) |
| 109 | Yield { value = shortcut (to_op k); state = `start } | ||
| 110 | | `chord_reg r, k when is_instant_operation k -> | 109 | | `chord_reg r, k when is_instant_operation k -> |
| 111 | Yield { value = shortcut ~r (to_op k); state = `start } | 110 | (`start, shortcut ~r (to_op k)) |
| 112 | | `chord_fst_n (r, n), k when is_instant_operation k -> | 111 | | `chord_fst_n (r, n), k when is_instant_operation k -> |
| 113 | Yield { value = shortcut ?r ~n (to_op k); state = `start } | 112 | (`start, shortcut ?r ~n (to_op k)) |
| 114 | (* Chord operation (first) *) | 113 | (* Chord operation (first) *) |
| 115 | | `start, k when is_chord_operation k -> | 114 | | `start, k when is_chord_operation k -> |
| 116 | Yield { value = Partial k; state = `chord_cmd (None, None, to_op k) } | 115 | (`chord_cmd (None, None, to_op k), Partial k) |
| 117 | | `chord_reg r, k when is_chord_operation k -> | 116 | | `chord_reg r, k when is_chord_operation k -> |
| 118 | Yield { value = Partial k; state = `chord_cmd (Some r, None, to_op k) } | 117 | (`chord_cmd (Some r, None, to_op k), Partial k) |
| 119 | | `chord_fst_n (r, n), k when is_chord_operation k -> | 118 | | `chord_fst_n (r, n), k when is_chord_operation k -> |
| 120 | Yield { value = Partial k; state = `chord_cmd (r, Some n, to_op k) } | 119 | (`chord_cmd (r, Some n, to_op k), Partial k) |
| 121 | (* Count (second) *) | 120 | (* Count (second) *) |
| 122 | | `chord_cmd (r, n1, c), Key n when Char.('1' <= n && n <= '9') -> | 121 | | `chord_cmd (r, n1, c), Key n when Char.('1' <= n && n <= '9') -> |
| 123 | let n = Char.to_int n - 48 in | 122 | let n = Char.to_int n - 48 in |
| 124 | Yield { value = Partial k; state = `chord_snd_n (r, n1, c, n) } | 123 | (`chord_snd_n (r, n1, c, n), Partial k) |
| 125 | | `chord_snd_n (r, n1, c, n2), Key n when Char.('0' <= n && n <= '9') -> | 124 | | `chord_snd_n (r, n1, c, n2), Key n when Char.('0' <= n && n <= '9') -> |
| 126 | let n2 = (10 * n2) + Char.to_int n - 48 in | 125 | let n2 = (10 * n2) + Char.to_int n - 48 in |
| 127 | Yield { value = Partial k; state = `chord_snd_n (r, n1, c, n2) } | 126 | (`chord_snd_n (r, n1, c, n2), Partial k) |
| 128 | (* Chord operation (second) *) | 127 | (* Chord operation (second) *) |
| 129 | | `chord_cmd (r, n, c), k when is_chord_operation k && Poly.(c = to_op k) -> | 128 | | `chord_cmd (r, n, c), k when is_chord_operation k && Poly.(c = to_op k) -> |
| 130 | Yield { value = chord ?r ?n1:n c Line; state = `start } | 129 | (`start, chord ?r ?n1:n c Line) |
| 131 | | `chord_snd_n (r, n1, c, n2), k | 130 | | `chord_snd_n (r, n1, c, n2), k |
| 132 | when is_chord_operation k && Poly.(c = to_op k) -> | 131 | when is_chord_operation k && Poly.(c = to_op k) -> |
| 133 | Yield { value = chord ?r ?n1 c ~n2 Line; state = `start } | 132 | (`start, chord ?r ?n1 c ~n2 Line) |
| 134 | (* Movement *) | 133 | (* Movement *) |
| 135 | | (`start | `chord_reg _), k when is_simple_movement k -> | 134 | | (`start | `chord_reg _), k when is_simple_movement k -> |
| 136 | Yield { value = chord Noop (to_scope k); state = `start } | 135 | (`start, chord Noop (to_scope k)) |
| 137 | | `chord_fst_n (_, n), k when is_simple_movement k -> | 136 | | `chord_fst_n (_, n), k when is_simple_movement k -> |
| 138 | Yield { value = chord ~n1:n Noop (to_scope k); state = `start } | 137 | (`start, chord ~n1:n Noop (to_scope k)) |
| 139 | | `chord_cmd (r, n, c), k when is_simple_movement k -> | 138 | | `chord_cmd (r, n, c), k when is_simple_movement k -> |
| 140 | Yield { value = chord ?r ?n1:n c (to_scope k); state = `start } | 139 | (`start, chord ?r ?n1:n c (to_scope k)) |
| 141 | | `chord_snd_n (r, n1, c, n2), k when is_simple_movement k -> | 140 | | `chord_snd_n (r, n1, c, n2), k when is_simple_movement k -> |
| 142 | Yield { value = chord ?r ?n1 c ~n2 (to_scope k); state = `start } | 141 | (`start, chord ?r ?n1 c ~n2 (to_scope k)) |
| 143 | (* Catch-all rules *) | 142 | (* Catch-all rules *) |
| 144 | | `start, _ -> Yield { value = Simple k; state = `start } | 143 | | `start, _ -> (`start, Simple k) |
| 145 | | _, _ -> Skip { state = `start } | 144 | | _, _ -> (`start, Reset) |
| 146 | in | 145 | in |
| 147 | Sequence.unfold_with ~init:`start ~f:step Key.stream | 146 | Sequence.folding_map ~init:`start ~f:step Key.stream |
diff --git a/lib/editor.ml b/lib/editor.ml index c34d558..230f13a 100644 --- a/lib/editor.ml +++ b/lib/editor.ml | |||
| @@ -12,13 +12,13 @@ type editor = { | |||
| 12 | cursor : cursor; | 12 | cursor : cursor; |
| 13 | buffer : Buffer.t option; | 13 | buffer : Buffer.t option; |
| 14 | rendered : bool; | 14 | rendered : bool; |
| 15 | pending : Key.t Sequence.t; | 15 | istream : Command.t Sequence.t; |
| 16 | i_pending : Command.t Sequence.t; | 16 | nstream : Command.t Sequence.t; |
| 17 | n_pending : Command.t Sequence.t; | ||
| 18 | status_size : int; | 17 | status_size : int; |
| 19 | message : string option; | 18 | message : string option; |
| 20 | message_timestamp : float; | 19 | message_timestamp : float; |
| 21 | message_duration : float; | 20 | message_duration : float; |
| 21 | pending_command : string; | ||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | type t = editor | 24 | type t = editor |
| @@ -31,13 +31,13 @@ let init (c : Config.t) : editor = | |||
| 31 | cursor = (1, 1); | 31 | cursor = (1, 1); |
| 32 | buffer = List.hd c.files |> Option.map ~f:Buffer.from_file; | 32 | buffer = List.hd c.files |> Option.map ~f:Buffer.from_file; |
| 33 | rendered = true; | 33 | rendered = true; |
| 34 | pending = Key.stream; | 34 | istream = Command.i_stream; |
| 35 | i_pending = Command.i_stream; | 35 | nstream = Command.n_stream; |
| 36 | n_pending = Command.n_stream; | ||
| 37 | status_size = 2; | 36 | status_size = 2; |
| 38 | message = Some "Hello, control line!"; | 37 | message = Some "Hello, control line!"; |
| 39 | message_timestamp = Unix.time (); | 38 | message_timestamp = Unix.time (); |
| 40 | message_duration = 5.; | 39 | message_duration = 5.; |
| 40 | pending_command = ""; | ||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | let string_of_mode = function | 43 | let string_of_mode = function |
| @@ -80,8 +80,9 @@ let statusbar e = | |||
| 80 | ~fill:' ' w | 80 | ~fill:' ' w |
| 81 | |> invert | 81 | |> invert |
| 82 | and control = | 82 | and control = |
| 83 | let msg = Option.value ~default:"" e.message |> sequence_of_string in | 83 | let msg = Option.value ~default:"" e.message |> sequence_of_string |
| 84 | spread ~l:msg ~fill:' ' w | 84 | and cmd = e.pending_command |> sequence_of_string in |
| 85 | spread ~l:msg ~r:cmd ~fill:' ' w | ||
| 85 | in | 86 | in |
| 86 | Sequence.(take (of_list [ status; control ]) e.status_size) | 87 | Sequence.(take (of_list [ status; control ]) e.status_size) |
| 87 | 88 | ||
| @@ -187,6 +188,14 @@ module Action = struct | |||
| 187 | let set_message m e = | 188 | let set_message m e = |
| 188 | ((), { e with message = m; message_timestamp = Unix.time () }) | 189 | ((), { e with message = m; message_timestamp = Unix.time () }) |
| 189 | 190 | ||
| 191 | let get_pending_command e = (e.pending_command, e) | ||
| 192 | let set_pending_command p e = ((), { e with pending_command = p }) | ||
| 193 | |||
| 194 | let append_pending_command k = | ||
| 195 | let aux p = p ^ Key.to_string k in | ||
| 196 | get_pending_command >>| aux >>= set_pending_command | ||
| 197 | |||
| 198 | let clear_pending_command = set_pending_command "" | ||
| 190 | 199 | ||
| 191 | let tick = | 200 | let tick = |
| 192 | let check_message_timestamp e = | 201 | let check_message_timestamp e = |
| @@ -285,6 +294,7 @@ let handle_insert_command = | |||
| 285 | (Buffer.Action.move_left |> on_focused_buffer) *> set_mode Normal | 294 | (Buffer.Action.move_left |> on_focused_buffer) *> set_mode Normal |
| 286 | | Simple Page_down | Simple (Ctrl 'F') -> | 295 | | Simple Page_down | Simple (Ctrl 'F') -> |
| 287 | fun e -> | 296 | fun e -> |
| 297 | (* TODO consider using the buffer window size (i.e., subtract status_size) *) | ||
| 288 | let (n, _), e = get_terminal_size e in | 298 | let (n, _), e = get_terminal_size e in |
| 289 | on_focused_buffer (Buffer.Action.move_down ~n) e | 299 | on_focused_buffer (Buffer.Action.move_down ~n) e |
| 290 | | Simple Page_up | Simple (Ctrl 'B') -> | 300 | | Simple Page_up | Simple (Ctrl 'B') -> |
| @@ -305,151 +315,159 @@ let handle_insert_command = | |||
| 305 | | Type k -> Buffer.Action.insert k |> on_focused_buffer | 315 | | Type k -> Buffer.Action.insert k |> on_focused_buffer |
| 306 | | _ -> noop | 316 | | _ -> noop |
| 307 | 317 | ||
| 308 | let handle_normal_command = | 318 | let handle_normal_command c = |
| 309 | let open Command in | 319 | let open Command in |
| 310 | let open Action in | 320 | let open Action in |
| 311 | function | 321 | let update_command_cue = |
| 312 | (* Movements *) | 322 | match c with |
| 313 | | Chord (_, n, Noop, _, Down) -> | 323 | | Partial k -> append_pending_command k |
| 314 | Buffer.Action.move_down ?n |> on_focused_buffer | 324 | | _ -> clear_pending_command |
| 315 | | Chord (_, n, Noop, _, Left) -> | 325 | and compute_action = |
| 316 | Buffer.Action.move_left ?n |> on_focused_buffer | 326 | match c with |
| 317 | | Chord (_, n, Noop, _, Right) -> | 327 | (* Movements *) |
| 318 | Buffer.Action.move_right ?n |> on_focused_buffer | 328 | | Chord (_, n, Noop, _, Down) -> |
| 319 | | Chord (_, n, Noop, _, Up) -> Buffer.Action.move_up ?n |> on_focused_buffer | 329 | Buffer.Action.move_down ?n |> on_focused_buffer |
| 320 | | Chord (_, n, Noop, _, To_bol) -> | 330 | | Chord (_, n, Noop, _, Left) -> |
| 321 | let n = Option.value ~default:1 n - 1 in | 331 | Buffer.Action.move_left ?n |> on_focused_buffer |
| 322 | Buffer.Action.(move_down ~n &> bol) |> on_focused_buffer | 332 | | Chord (_, n, Noop, _, Right) -> |
| 323 | | Chord (_, n, Noop, _, To_eol) -> | 333 | Buffer.Action.move_right ?n |> on_focused_buffer |
| 324 | let n = Option.value ~default:1 n - 1 in | 334 | | Chord (_, n, Noop, _, Up) -> Buffer.Action.move_up ?n |> on_focused_buffer |
| 325 | Buffer.Action.(move_down ~n &> eol) |> on_focused_buffer | 335 | | Chord (_, n, Noop, _, To_bol) -> |
| 326 | | Simple Page_down | Simple (Ctrl 'F') -> | 336 | let n = Option.value ~default:1 n - 1 in |
| 327 | fun e -> | 337 | Buffer.Action.(move_down ~n &> bol) |> on_focused_buffer |
| 328 | let (n, _), e = get_terminal_size e in | 338 | | Chord (_, n, Noop, _, To_eol) -> |
| 329 | on_focused_buffer (Buffer.Action.move_down ~n) e | 339 | let n = Option.value ~default:1 n - 1 in |
| 330 | | Simple Page_up | Simple (Ctrl 'B') -> | 340 | Buffer.Action.(move_down ~n &> eol) |> on_focused_buffer |
| 331 | fun e -> | 341 | | Simple Page_down | Simple (Ctrl 'F') -> |
| 332 | let (n, _), e = get_terminal_size e in | 342 | fun e -> |
| 333 | on_focused_buffer (Buffer.Action.move_up ~n) e | 343 | let (n, _), e = get_terminal_size e in |
| 334 | | Simple (Ctrl 'D') -> | 344 | on_focused_buffer (Buffer.Action.move_down ~n) e |
| 335 | fun e -> | 345 | | Simple Page_up | Simple (Ctrl 'B') -> |
| 336 | let (r, _), e = get_terminal_size e in | 346 | fun e -> |
| 337 | on_focused_buffer (Buffer.Action.move_down ~n:(r / 2)) e | 347 | let (n, _), e = get_terminal_size e in |
| 338 | | Simple (Ctrl 'U') -> | 348 | on_focused_buffer (Buffer.Action.move_up ~n) e |
| 339 | fun e -> | 349 | | Simple (Ctrl 'D') -> |
| 340 | let (r, _), e = get_terminal_size e in | 350 | fun e -> |
| 341 | on_focused_buffer (Buffer.Action.move_up ~n:(r / 2)) e | 351 | let (r, _), e = get_terminal_size e in |
| 342 | (* Change *) | 352 | on_focused_buffer (Buffer.Action.move_down ~n:(r / 2)) e |
| 343 | | Shortcut (_, n, Change) -> | 353 | | Simple (Ctrl 'U') -> |
| 344 | let n = Option.value ~default:1 n - 1 in | 354 | fun e -> |
| 345 | (Buffer.Action.( | 355 | let (r, _), e = get_terminal_size e in |
| 346 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) | 356 | on_focused_buffer (Buffer.Action.move_up ~n:(r / 2)) e |
| 347 | |> on_focused_buffer_or_new) | 357 | (* Change *) |
| 348 | *> set_mode Insert | 358 | | Shortcut (_, n, Change) -> |
| 349 | | Chord (_, n1, Change, n2, Line) -> | 359 | let n = Option.value ~default:1 n - 1 in |
| 350 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in | 360 | (Buffer.Action.( |
| 351 | (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) | 361 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) |
| 352 | |> on_focused_buffer_or_new) | 362 | |> on_focused_buffer_or_new) |
| 353 | *> set_mode Insert | 363 | *> set_mode Insert |
| 354 | | Chord (_, n1, Change, n2, Down) -> | 364 | | Chord (_, n1, Change, n2, Line) -> |
| 355 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 365 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in |
| 356 | (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) | 366 | (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) |
| 357 | |> on_focused_buffer_or_new) | 367 | |> on_focused_buffer_or_new) |
| 358 | *> set_mode Insert | 368 | *> set_mode Insert |
| 359 | | Chord (_, n1, Change, n2, Left) -> | 369 | | Chord (_, n1, Change, n2, Down) -> |
| 360 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 370 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 361 | (Buffer.Action.delete_before ~n |> on_focused_buffer_or_new) | 371 | (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) |
| 362 | *> set_mode Insert | 372 | |> on_focused_buffer_or_new) |
| 363 | | Chord (_, n1, Change, n2, Right) -> | 373 | *> set_mode Insert |
| 364 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 374 | | Chord (_, n1, Change, n2, Left) -> |
| 365 | (Buffer.Action.delete_after ~n |> on_focused_buffer_or_new) | 375 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 366 | *> set_mode Insert | 376 | (Buffer.Action.delete_before ~n |> on_focused_buffer_or_new) |
| 367 | | Chord (_, n1, Change, n2, Up) -> | 377 | *> set_mode Insert |
| 368 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 378 | | Chord (_, n1, Change, n2, Right) -> |
| 369 | (Buffer.Action.(bol &> delete_to_eol &> delete_lines_before ~n) | 379 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 370 | |> on_focused_buffer_or_new) | 380 | (Buffer.Action.delete_after ~n |> on_focused_buffer_or_new) |
| 371 | *> set_mode Insert | 381 | *> set_mode Insert |
| 372 | | Chord (_, n1, Change, n2, To_bol) -> | 382 | | Chord (_, n1, Change, n2, Up) -> |
| 373 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in | 383 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 374 | (Buffer.Action.( | 384 | (Buffer.Action.(bol &> delete_to_eol &> delete_lines_before ~n) |
| 375 | delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) | 385 | |> on_focused_buffer_or_new) |
| 376 | |> on_focused_buffer_or_new) | 386 | *> set_mode Insert |
| 377 | *> set_mode Insert | 387 | | Chord (_, n1, Change, n2, To_bol) -> |
| 378 | | Chord (_, n1, Change, n2, To_eol) -> | 388 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in |
| 379 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in | 389 | (Buffer.Action.( |
| 380 | (Buffer.Action.( | 390 | delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) |
| 381 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) | 391 | |> on_focused_buffer_or_new) |
| 382 | |> on_focused_buffer_or_new) | 392 | *> set_mode Insert |
| 383 | *> set_mode Insert | 393 | | Chord (_, n1, Change, n2, To_eol) -> |
| 384 | (* Delete *) | 394 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in |
| 385 | | Shortcut (_, n, Delete) -> | 395 | (Buffer.Action.( |
| 386 | let n = Option.value ~default:1 n - 1 in | 396 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) |
| 387 | Buffer.Action.( | 397 | |> on_focused_buffer_or_new) |
| 388 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) | 398 | *> set_mode Insert |
| 389 | |> on_focused_buffer_or_new | 399 | (* Delete *) |
| 390 | | Chord (_, n1, Delete, n2, Line) -> | 400 | | Shortcut (_, n, Delete) -> |
| 391 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 401 | let n = Option.value ~default:1 n - 1 in |
| 392 | Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new | 402 | Buffer.Action.( |
| 393 | | Chord (_, n1, Delete, n2, Down) -> | 403 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) |
| 394 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in | 404 | |> on_focused_buffer_or_new |
| 395 | Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new | 405 | | Chord (_, n1, Delete, n2, Line) -> |
| 396 | | Chord (_, n1, Delete, n2, Left) -> | 406 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 397 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 407 | Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new |
| 398 | Buffer.Action.delete_before ~n |> on_focused_buffer_or_new | 408 | | Chord (_, n1, Delete, n2, Down) -> |
| 399 | | Shortcut (_, n, Erase_before) -> | 409 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in |
| 400 | let n = Option.(value ~default:1 n) in | 410 | Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new |
| 401 | Buffer.Action.delete_before ~n |> on_focused_buffer_or_new | 411 | | Chord (_, n1, Delete, n2, Left) -> |
| 402 | | Chord (_, n1, Delete, n2, Right) -> | 412 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 403 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 413 | Buffer.Action.delete_before ~n |> on_focused_buffer_or_new |
| 404 | Buffer.Action.delete_after ~n |> on_focused_buffer_or_new | 414 | | Shortcut (_, n, Erase_before) -> |
| 405 | | Shortcut (_, n, Erase_after) -> | 415 | let n = Option.(value ~default:1 n) in |
| 406 | let n = Option.(value ~default:1 n) in | 416 | Buffer.Action.delete_before ~n |> on_focused_buffer_or_new |
| 407 | Buffer.Action.delete_after ~n |> on_focused_buffer_or_new | 417 | | Chord (_, n1, Delete, n2, Right) -> |
| 408 | | Chord (_, n1, Delete, n2, Up) -> | 418 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 409 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in | 419 | Buffer.Action.delete_after ~n |> on_focused_buffer_or_new |
| 410 | Buffer.Action.(delete_lines ~n:1 &> delete_lines_before ~n) | 420 | | Shortcut (_, n, Erase_after) -> |
| 411 | |> on_focused_buffer_or_new | 421 | let n = Option.(value ~default:1 n) in |
| 412 | | Chord (_, n1, Delete, n2, To_bol) -> | 422 | Buffer.Action.delete_after ~n |> on_focused_buffer_or_new |
| 413 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in | 423 | | Chord (_, n1, Delete, n2, Up) -> |
| 414 | Buffer.Action.( | 424 | let n = Option.(value ~default:1 n1 * value ~default:1 n2) in |
| 415 | delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) | 425 | Buffer.Action.(delete_lines ~n:1 &> delete_lines_before ~n) |
| 416 | |> on_focused_buffer_or_new | 426 | |> on_focused_buffer_or_new |
| 417 | | Chord (_, n1, Delete, n2, To_eol) -> | 427 | | Chord (_, n1, Delete, n2, To_bol) -> |
| 418 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in | 428 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in |
| 419 | Buffer.Action.( | 429 | Buffer.Action.( |
| 420 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) | 430 | delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) |
| 421 | |> on_focused_buffer_or_new | 431 | |> on_focused_buffer_or_new |
| 422 | (* Join *) | 432 | | Chord (_, n1, Delete, n2, To_eol) -> |
| 423 | | Shortcut (_, n, Join) -> | 433 | let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in |
| 424 | let n = Option.(value ~default:1 n) in | 434 | Buffer.Action.( |
| 425 | Buffer.Action.join_lines ~n |> on_focused_buffer_or_new | 435 | delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) |
| 426 | (* Quit *) | 436 | |> on_focused_buffer_or_new |
| 427 | | Simple (Ctrl 'Q') -> quit 0 | 437 | (* Join *) |
| 428 | (* Misc *) | 438 | | Shortcut (_, n, Join) -> |
| 429 | | Simple (Key 'A') -> | 439 | let n = Option.(value ~default:1 n) in |
| 430 | (Buffer.Action.eol |> on_focused_buffer_or_new) *> set_mode Insert | 440 | Buffer.Action.join_lines ~n |> on_focused_buffer_or_new |
| 431 | | Simple (Key 'a') -> | 441 | (* Quit *) |
| 432 | (Buffer.Action.move_right |> on_focused_buffer_or_new) *> set_mode Insert | 442 | | Simple (Ctrl 'Q') -> quit 0 |
| 433 | (* | Key 'G' -> Buffer.Action.eof |> on_focused_buffer_or_new *) | 443 | (* Misc *) |
| 434 | (* | Key 'I' -> noop *) | 444 | | Simple (Key 'A') -> |
| 435 | | Simple (Key 'i') -> (Fn.id |> on_focused_buffer_or_new) *> set_mode Insert | 445 | (Buffer.Action.eol |> on_focused_buffer_or_new) *> set_mode Insert |
| 436 | (* | Key 's' -> *) | 446 | | Simple (Key 'a') -> |
| 437 | (* (Buffer.Action.delete_after |> on_focused_buffer_or_new) *) | 447 | (Buffer.Action.move_right |> on_focused_buffer_or_new) |
| 438 | (* *> set_mode Insert *) | 448 | *> set_mode Insert |
| 439 | (* Debug *) | 449 | (* | Key 'G' -> Buffer.Action.eof |> on_focused_buffer_or_new *) |
| 440 | | Simple (Ctrl 'R') -> toggle_rendered | 450 | (* | Key 'I' -> noop *) |
| 441 | | _ -> noop | 451 | | Simple (Key 'i') -> (Fn.id |> on_focused_buffer_or_new) *> set_mode Insert |
| 452 | (* | Key 's' -> *) | ||
| 453 | (* (Buffer.Action.delete_after |> on_focused_buffer_or_new) *) | ||
| 454 | (* *> set_mode Insert *) | ||
| 455 | (* Debug *) | ||
| 456 | | Simple (Ctrl 'R') -> toggle_rendered | ||
| 457 | | _ -> noop | ||
| 458 | in | ||
| 459 | compute_action *> update_command_cue | ||
| 442 | 460 | ||
| 443 | let handle_next_command m e = | 461 | let handle_next_command m e = |
| 444 | match m with | 462 | match m with |
| 445 | | Insert -> ( | 463 | | Insert -> ( |
| 446 | match Sequence.next e.i_pending with | 464 | match Sequence.next e.istream with |
| 447 | | None -> ((), e) | 465 | | None -> ((), e) |
| 448 | | Some (h, t) -> handle_insert_command h { e with i_pending = t }) | 466 | | Some (h, t) -> handle_insert_command h { e with istream = t }) |
| 449 | | Normal -> ( | 467 | | Normal -> ( |
| 450 | match Sequence.next e.n_pending with | 468 | match Sequence.next e.nstream with |
| 451 | | None -> ((), e) | 469 | | None -> ((), e) |
| 452 | | Some (h, t) -> handle_normal_command h { e with n_pending = t }) | 470 | | Some (h, t) -> handle_normal_command h { e with nstream = t }) |
| 453 | | Control -> failwith "unimplemented" | 471 | | Control -> failwith "unimplemented" |
| 454 | 472 | ||
| 455 | let handle_next_command = | 473 | let handle_next_command = |
| @@ -32,6 +32,25 @@ let of_char = function | |||
| 32 | | c when Char.(c < ' ') -> Char.to_int c + 64 |> Char.of_int_exn |> ctrl | 32 | | c when Char.(c < ' ') -> Char.to_int c + 64 |> Char.of_int_exn |> ctrl |
| 33 | | c -> Key c | 33 | | c -> Key c |
| 34 | 34 | ||
| 35 | let to_string = function | ||
| 36 | | Arrow_down -> "<down>" | ||
| 37 | | Arrow_left -> "<left>" | ||
| 38 | | Arrow_right -> "<right>" | ||
| 39 | | Arrow_up -> "<up>" | ||
| 40 | | Backspace -> "<backspace>" | ||
| 41 | | Ctrl c -> Printf.sprintf "<c-%c>" c | ||
| 42 | | Delete -> "<delete>" | ||
| 43 | | End -> "<end>" | ||
| 44 | | Enter -> "<cr>" | ||
| 45 | | Esc -> "<esc>" | ||
| 46 | | Home -> "<home>" | ||
| 47 | | Key ' ' -> "<space>" | ||
| 48 | | Key c -> String.of_char c | ||
| 49 | | Nul -> "<nil>" | ||
| 50 | | Page_down -> "<pgdown>" | ||
| 51 | | Page_up -> "<pgup>" | ||
| 52 | | Tab -> "<tab>" | ||
| 53 | |||
| 35 | let stream = | 54 | let stream = |
| 36 | let step s c = | 55 | let step s c = |
| 37 | let open Sequence.Step in | 56 | let open Sequence.Step in |
diff --git a/lib/text.ml b/lib/text.ml index ff1f727..218f5e1 100644 --- a/lib/text.ml +++ b/lib/text.ml | |||
| @@ -8,3 +8,12 @@ let center ~fill n text = | |||
| 8 | take (take padding len_p @ text @ padding) n | 8 | take (take padding len_p @ text @ padding) n |
| 9 | 9 | ||
| 10 | let extend ~fill n text = take (text @ repeat fill) n | 10 | let extend ~fill n text = take (text @ repeat fill) n |
| 11 | |||
| 12 | let spread ?(l = empty) ?(lsize = length l) ?(c = empty) ?(csize = length c) | ||
| 13 | ?(r = empty) ?(rsize = length r) ~fill w = | ||
| 14 | let lpad = take (repeat fill) ((w / 2) - lsize - (csize / 2) - 1) in | ||
| 15 | let rpad = take (repeat fill) ((w / 2) - rsize - (csize / 2)) in | ||
| 16 | l @ lpad @ c @ rpad @ r | ||
| 17 | |||
| 18 | let invert text = Terminal.(fmt_inverted_on @ text @ fmt_inverted_off) | ||
| 19 | let bold text = Terminal.(fmt_bold_on @ text @ fmt_bold_off) | ||
