From 5c3864986f844a31e0b6dbeec48543dc6376cff6 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Tue, 23 Jan 2024 18:11:22 +0100 Subject: feat: add partial chords to statusbar --- lib/editor.ml | 306 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 162 insertions(+), 144 deletions(-) (limited to 'lib/editor.ml') 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 = { cursor : cursor; buffer : Buffer.t option; rendered : bool; - pending : Key.t Sequence.t; - i_pending : Command.t Sequence.t; - n_pending : Command.t Sequence.t; + istream : Command.t Sequence.t; + nstream : Command.t Sequence.t; status_size : int; message : string option; message_timestamp : float; message_duration : float; + pending_command : string; } type t = editor @@ -31,13 +31,13 @@ let init (c : Config.t) : editor = cursor = (1, 1); buffer = List.hd c.files |> Option.map ~f:Buffer.from_file; rendered = true; - pending = Key.stream; - i_pending = Command.i_stream; - n_pending = Command.n_stream; + istream = Command.i_stream; + nstream = Command.n_stream; status_size = 2; message = Some "Hello, control line!"; message_timestamp = Unix.time (); message_duration = 5.; + pending_command = ""; } let string_of_mode = function @@ -80,8 +80,9 @@ let statusbar e = ~fill:' ' w |> invert and control = - let msg = Option.value ~default:"" e.message |> sequence_of_string in - spread ~l:msg ~fill:' ' w + let msg = Option.value ~default:"" e.message |> sequence_of_string + and cmd = e.pending_command |> sequence_of_string in + spread ~l:msg ~r:cmd ~fill:' ' w in Sequence.(take (of_list [ status; control ]) e.status_size) @@ -187,6 +188,14 @@ module Action = struct let set_message m e = ((), { e with message = m; message_timestamp = Unix.time () }) + let get_pending_command e = (e.pending_command, e) + let set_pending_command p e = ((), { e with pending_command = p }) + + let append_pending_command k = + let aux p = p ^ Key.to_string k in + get_pending_command >>| aux >>= set_pending_command + + let clear_pending_command = set_pending_command "" let tick = let check_message_timestamp e = @@ -285,6 +294,7 @@ let handle_insert_command = (Buffer.Action.move_left |> on_focused_buffer) *> set_mode Normal | Simple Page_down | Simple (Ctrl 'F') -> fun e -> + (* TODO consider using the buffer window size (i.e., subtract status_size) *) let (n, _), e = get_terminal_size e in on_focused_buffer (Buffer.Action.move_down ~n) e | Simple Page_up | Simple (Ctrl 'B') -> @@ -305,151 +315,159 @@ let handle_insert_command = | Type k -> Buffer.Action.insert k |> on_focused_buffer | _ -> noop -let handle_normal_command = +let handle_normal_command c = let open Command in let open Action in - function - (* Movements *) - | Chord (_, n, Noop, _, Down) -> - Buffer.Action.move_down ?n |> on_focused_buffer - | Chord (_, n, Noop, _, Left) -> - Buffer.Action.move_left ?n |> on_focused_buffer - | Chord (_, n, Noop, _, Right) -> - Buffer.Action.move_right ?n |> on_focused_buffer - | Chord (_, n, Noop, _, Up) -> Buffer.Action.move_up ?n |> on_focused_buffer - | Chord (_, n, Noop, _, To_bol) -> - let n = Option.value ~default:1 n - 1 in - Buffer.Action.(move_down ~n &> bol) |> on_focused_buffer - | Chord (_, n, Noop, _, To_eol) -> - let n = Option.value ~default:1 n - 1 in - Buffer.Action.(move_down ~n &> eol) |> on_focused_buffer - | Simple Page_down | Simple (Ctrl 'F') -> - fun e -> - let (n, _), e = get_terminal_size e in - on_focused_buffer (Buffer.Action.move_down ~n) e - | Simple Page_up | Simple (Ctrl 'B') -> - fun e -> - let (n, _), e = get_terminal_size e in - on_focused_buffer (Buffer.Action.move_up ~n) e - | Simple (Ctrl 'D') -> - fun e -> - let (r, _), e = get_terminal_size e in - on_focused_buffer (Buffer.Action.move_down ~n:(r / 2)) e - | Simple (Ctrl 'U') -> - fun e -> - let (r, _), e = get_terminal_size e in - on_focused_buffer (Buffer.Action.move_up ~n:(r / 2)) e - (* Change *) - | Shortcut (_, n, Change) -> - let n = Option.value ~default:1 n - 1 in - (Buffer.Action.( - delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) - |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, Line) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in - (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) - |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, Down) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) - |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, Left) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - (Buffer.Action.delete_before ~n |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, Right) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - (Buffer.Action.delete_after ~n |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, Up) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - (Buffer.Action.(bol &> delete_to_eol &> delete_lines_before ~n) - |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, To_bol) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in - (Buffer.Action.( - delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) - |> on_focused_buffer_or_new) - *> set_mode Insert - | Chord (_, n1, Change, n2, To_eol) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in - (Buffer.Action.( - delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) - |> on_focused_buffer_or_new) - *> set_mode Insert - (* Delete *) - | Shortcut (_, n, Delete) -> - let n = Option.value ~default:1 n - 1 in - Buffer.Action.( - delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) - |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, Line) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, Down) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in - Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, Left) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - Buffer.Action.delete_before ~n |> on_focused_buffer_or_new - | Shortcut (_, n, Erase_before) -> - let n = Option.(value ~default:1 n) in - Buffer.Action.delete_before ~n |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, Right) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - Buffer.Action.delete_after ~n |> on_focused_buffer_or_new - | Shortcut (_, n, Erase_after) -> - let n = Option.(value ~default:1 n) in - Buffer.Action.delete_after ~n |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, Up) -> - let n = Option.(value ~default:1 n1 * value ~default:1 n2) in - Buffer.Action.(delete_lines ~n:1 &> delete_lines_before ~n) - |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, To_bol) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in - Buffer.Action.( - delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) - |> on_focused_buffer_or_new - | Chord (_, n1, Delete, n2, To_eol) -> - let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in - Buffer.Action.( - delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) - |> on_focused_buffer_or_new - (* Join *) - | Shortcut (_, n, Join) -> - let n = Option.(value ~default:1 n) in - Buffer.Action.join_lines ~n |> on_focused_buffer_or_new - (* Quit *) - | Simple (Ctrl 'Q') -> quit 0 - (* Misc *) - | Simple (Key 'A') -> - (Buffer.Action.eol |> on_focused_buffer_or_new) *> set_mode Insert - | Simple (Key 'a') -> - (Buffer.Action.move_right |> on_focused_buffer_or_new) *> set_mode Insert - (* | Key 'G' -> Buffer.Action.eof |> on_focused_buffer_or_new *) - (* | Key 'I' -> noop *) - | Simple (Key 'i') -> (Fn.id |> on_focused_buffer_or_new) *> set_mode Insert - (* | Key 's' -> *) - (* (Buffer.Action.delete_after |> on_focused_buffer_or_new) *) - (* *> set_mode Insert *) - (* Debug *) - | Simple (Ctrl 'R') -> toggle_rendered - | _ -> noop + let update_command_cue = + match c with + | Partial k -> append_pending_command k + | _ -> clear_pending_command + and compute_action = + match c with + (* Movements *) + | Chord (_, n, Noop, _, Down) -> + Buffer.Action.move_down ?n |> on_focused_buffer + | Chord (_, n, Noop, _, Left) -> + Buffer.Action.move_left ?n |> on_focused_buffer + | Chord (_, n, Noop, _, Right) -> + Buffer.Action.move_right ?n |> on_focused_buffer + | Chord (_, n, Noop, _, Up) -> Buffer.Action.move_up ?n |> on_focused_buffer + | Chord (_, n, Noop, _, To_bol) -> + let n = Option.value ~default:1 n - 1 in + Buffer.Action.(move_down ~n &> bol) |> on_focused_buffer + | Chord (_, n, Noop, _, To_eol) -> + let n = Option.value ~default:1 n - 1 in + Buffer.Action.(move_down ~n &> eol) |> on_focused_buffer + | Simple Page_down | Simple (Ctrl 'F') -> + fun e -> + let (n, _), e = get_terminal_size e in + on_focused_buffer (Buffer.Action.move_down ~n) e + | Simple Page_up | Simple (Ctrl 'B') -> + fun e -> + let (n, _), e = get_terminal_size e in + on_focused_buffer (Buffer.Action.move_up ~n) e + | Simple (Ctrl 'D') -> + fun e -> + let (r, _), e = get_terminal_size e in + on_focused_buffer (Buffer.Action.move_down ~n:(r / 2)) e + | Simple (Ctrl 'U') -> + fun e -> + let (r, _), e = get_terminal_size e in + on_focused_buffer (Buffer.Action.move_up ~n:(r / 2)) e + (* Change *) + | Shortcut (_, n, Change) -> + let n = Option.value ~default:1 n - 1 in + (Buffer.Action.( + delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) + |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, Line) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in + (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) + |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, Down) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + (Buffer.Action.(delete_lines ~n &> bol &> delete_to_eol) + |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, Left) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + (Buffer.Action.delete_before ~n |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, Right) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + (Buffer.Action.delete_after ~n |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, Up) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + (Buffer.Action.(bol &> delete_to_eol &> delete_lines_before ~n) + |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, To_bol) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in + (Buffer.Action.( + delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) + |> on_focused_buffer_or_new) + *> set_mode Insert + | Chord (_, n1, Change, n2, To_eol) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in + (Buffer.Action.( + delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) + |> on_focused_buffer_or_new) + *> set_mode Insert + (* Delete *) + | Shortcut (_, n, Delete) -> + let n = Option.value ~default:1 n - 1 in + Buffer.Action.( + delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) + |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, Line) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, Down) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) + 1) in + Buffer.Action.delete_lines ~n |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, Left) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + Buffer.Action.delete_before ~n |> on_focused_buffer_or_new + | Shortcut (_, n, Erase_before) -> + let n = Option.(value ~default:1 n) in + Buffer.Action.delete_before ~n |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, Right) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + Buffer.Action.delete_after ~n |> on_focused_buffer_or_new + | Shortcut (_, n, Erase_after) -> + let n = Option.(value ~default:1 n) in + Buffer.Action.delete_after ~n |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, Up) -> + let n = Option.(value ~default:1 n1 * value ~default:1 n2) in + Buffer.Action.(delete_lines ~n:1 &> delete_lines_before ~n) + |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, To_bol) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in + Buffer.Action.( + delete_to_bol &> move_down &> delete_lines ~n &> move_up &> bol) + |> on_focused_buffer_or_new + | Chord (_, n1, Delete, n2, To_eol) -> + let n = Option.((value ~default:1 n1 * value ~default:1 n2) - 1) in + Buffer.Action.( + delete_to_eol &> move_down &> delete_lines ~n &> move_up &> eol) + |> on_focused_buffer_or_new + (* Join *) + | Shortcut (_, n, Join) -> + let n = Option.(value ~default:1 n) in + Buffer.Action.join_lines ~n |> on_focused_buffer_or_new + (* Quit *) + | Simple (Ctrl 'Q') -> quit 0 + (* Misc *) + | Simple (Key 'A') -> + (Buffer.Action.eol |> on_focused_buffer_or_new) *> set_mode Insert + | Simple (Key 'a') -> + (Buffer.Action.move_right |> on_focused_buffer_or_new) + *> set_mode Insert + (* | Key 'G' -> Buffer.Action.eof |> on_focused_buffer_or_new *) + (* | Key 'I' -> noop *) + | Simple (Key 'i') -> (Fn.id |> on_focused_buffer_or_new) *> set_mode Insert + (* | Key 's' -> *) + (* (Buffer.Action.delete_after |> on_focused_buffer_or_new) *) + (* *> set_mode Insert *) + (* Debug *) + | Simple (Ctrl 'R') -> toggle_rendered + | _ -> noop + in + compute_action *> update_command_cue let handle_next_command m e = match m with | Insert -> ( - match Sequence.next e.i_pending with + match Sequence.next e.istream with | None -> ((), e) - | Some (h, t) -> handle_insert_command h { e with i_pending = t }) + | Some (h, t) -> handle_insert_command h { e with istream = t }) | Normal -> ( - match Sequence.next e.n_pending with + match Sequence.next e.nstream with | None -> ((), e) - | Some (h, t) -> handle_normal_command h { e with n_pending = t }) + | Some (h, t) -> handle_normal_command h { e with nstream = t }) | Control -> failwith "unimplemented" let handle_next_command = -- cgit v1.2.3