diff --git a/examples/key_map/dune b/examples/key_map/dune new file mode 100644 index 0000000..b54f018 --- /dev/null +++ b/examples/key_map/dune @@ -0,0 +1,3 @@ +(executable + (name main) + (libraries minttea spices leaves)) diff --git a/examples/key_map/main.ml b/examples/key_map/main.ml new file mode 100644 index 0000000..262a6cc --- /dev/null +++ b/examples/key_map/main.ml @@ -0,0 +1,48 @@ +open Leaves +open Minttea + +type msg = CursorUp | CursorDown | CursorLeft + +let defaults = + let open Key_map in + make [ + on + ~help:{ key = "up"; desc = "↑/k" } + [ Minttea.Event.Up; Minttea.Event.Key "k" ] + CursorUp; + on + ~help:{ key = "down"; desc = "↓/j" } + [ Minttea.Event.Down; Minttea.Event.Key "j" ] + CursorDown; + on ~disabled:true + ~help:{ key = "left"; desc = "←/h" } + [ Minttea.Event.Left; Minttea.Event.Key "h" ] + CursorLeft; + ] + +let custom_key_map = + let open Key_map in + [ + on + ~help:{ key = "up"; desc = "↑/k" } + [ Minttea.Event.Up; Minttea.Event.Key "k"; Minttea.Event.Key "u" ] + CursorUp; + ] + +let () = + List.iter + (fun k -> + match Key_map.find_match ~custom_key_map k defaults with + | Some CursorUp -> print_endline "up" + | Some CursorDown -> print_endline "down" + | Some CursorLeft -> print_endline "left" + | None -> print_endline "Not Found") + [ + Event.Up; + Event.Key "k"; + Event.Key "u"; + Event.Down; + Event.Key "j"; + Event.Left; + Event.Enter; + ] diff --git a/leaves/key_map.ml b/leaves/key_map.ml new file mode 100644 index 0000000..89fce53 --- /dev/null +++ b/leaves/key_map.ml @@ -0,0 +1,32 @@ +type help = { key : string; desc : string } + +type binding = { + keys : Minttea.Event.key list; + help : help option; + disabled : bool; +} + +type 'a t = ('a * binding) list + +let on ?help ?(disabled = false) keys msg = (msg, { keys; help; disabled }) + +let find_match ?(custom_key_map : 'a t option) key (default_key_map : 'a t) = + let key_map = + match custom_key_map with + | Some k_map -> + List.fold_left + (fun acc (k, b) -> + if List.mem_assoc k acc then acc else List.cons (k, b) acc) + k_map default_key_map + | None -> default_key_map + in + + let f (_, (binding : binding)) = + if binding.disabled then false + else List.exists (fun k -> k == key) binding.keys + in + List.find_opt f key_map |> Option.map (fun (msg, _) -> msg) + +(* INFO: This is just for future proofing, in case the underlying type changes *) +let make (key_map : ('a * binding) list) = key_map +let to_list (key_map : 'a t) = key_map diff --git a/leaves/key_map.mli b/leaves/key_map.mli new file mode 100644 index 0000000..70930fa --- /dev/null +++ b/leaves/key_map.mli @@ -0,0 +1,26 @@ +type help = { key : string; desc : string } + +type binding = { + keys : Minttea.Event.key list; + help : help option; + disabled : bool; +} + +type 'a t = ('a * binding) list + +val on : + ?help:help -> + ?disabled:bool -> + Minttea.Event.key list -> + 'a -> + 'a * binding + +val find_match : + ?custom_key_map:'a t -> + Minttea.Event.key -> + 'a t -> + 'a option + +val make : ('a * binding) list -> 'a t +val to_list : 'a t -> ('a * binding) list +