{"id":20888021,"url":"https://github.com/canop/crokey","last_synced_at":"2025-05-12T20:30:47.176Z","repository":{"id":44640880,"uuid":"453750172","full_name":"Canop/crokey","owner":"Canop","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-04T07:50:58.000Z","size":137,"stargazers_count":27,"open_issues_count":1,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-09T16:41:24.071Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Canop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-30T17:29:07.000Z","updated_at":"2025-05-04T07:51:01.000Z","dependencies_parsed_at":"2024-04-23T17:37:49.683Z","dependency_job_id":"655da067-7a22-4550-8ca0-235ad4012d8d","html_url":"https://github.com/Canop/crokey","commit_stats":{"total_commits":36,"total_committers":3,"mean_commits":12.0,"dds":"0.36111111111111116","last_synced_commit":"2c9a18e5d1660d1e411e17ef70c1624cab05a931"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fcrokey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fcrokey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fcrokey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fcrokey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Canop","download_url":"https://codeload.github.com/Canop/crokey/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253816656,"owners_count":21968861,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T08:23:49.873Z","updated_at":"2025-05-12T20:30:46.796Z","avatar_url":"https://github.com/Canop.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![MIT][s2]][l2] [![Latest Version][s1]][l1] [![docs][s3]][l3] [![Chat on Miaou][s4]][l4]\n\n[s1]: https://img.shields.io/crates/v/crokey.svg\n[l1]: https://crates.io/crates/crokey\n\n[s2]: https://img.shields.io/badge/license-MIT-blue.svg\n[l2]: LICENSE\n\n[s3]: https://docs.rs/crokey/badge.svg\n[l3]: https://docs.rs/crokey/\n\n[s4]: https://miaou.dystroy.org/static/shields/room.svg\n[l4]: https://miaou.dystroy.org/3490?crokey\n\n# Crokey\n\nCrokey helps incorporate configurable keybindings in [crossterm](https://github.com/crossterm-rs/crossterm)\nbased terminal applications by providing functions\n- parsing key combinations from strings\n- describing key combinations in strings\n- parsing key combinations at compile time\n- combining Crossterm key events in key combinations\n\n## The KeyCombination\n\nA `KeyCombination` is made of 1 to 3 \"normal\" keys with some optional modifiers (alt, shift, ctrl).\n\nIt can be parsed, ergonomically built with the `key!` macro, obtained from key events.\n\n## The Combiner\n\nWith a `Combiner`, you can change raw Crossterm key events into key combinations.\n\nWhen the terminal is modern enough and supports the Kitty protocol, complex combinations with up to three non-modifier keys may be formed, for example `Ctrl-Alt-Shift-g-y` or `Space-!`.\n\nFor standard ANSI terminals, only regular combinations are available, like `Shift-o`, `Ctrl-Alt-Shift-g` or `i`.\n\nThe combiner works in both cases:\nif you presses the `ctrl`, `i`, and `u ` keys at the same time, it will result in one combination (`ctrl-i-u`) on a kitty-compatible terminal, and as a sequence of 2 key combinations (`ctrl-i` then `ctrl-u` assuming you started pressing the `i` before the `u`) in other terminals.\n\nThe `print_key` example shows how to deal with that:\n\n```rust\nlet fmt = KeyCombinationFormat::default();\nlet mut combiner = Combiner::default();\nlet combines = combiner.enable_combining().unwrap();\nif combines {\n    println!(\"Your terminal supports combining keys\");\n} else {\n    println!(\"Your terminal doesn't support combining non-modifier keys\");\n}\nprintln!(\"Type any key combination\");\nloop {\n    terminal::enable_raw_mode().unwrap();\n    let e = read();\n    terminal::disable_raw_mode().unwrap();\n    match e {\n        Ok(Event::Key(key_event)) =\u003e {\n            if let Some(key_combination) = combiner.transform(key_event) {\n                match key_combination {\n                    key!(ctrl-c) | key!(ctrl-q) =\u003e {\n                        println!(\"quitting\");\n                        break;\n                    }\n                    _ =\u003e {\n                        println!(\"You typed {}\", fmt.to_string(key_combination));\n                    }\n                }\n            }\n        },\n        ...\n    }\n}\n```\n\n## Parse a string\n\nThose strings are usually provided by a configuration file.\n\n```rust\nuse crossterm::event::{KeyCode, KeyEvent, KeyModifiers};\nassert_eq!(\n    crokey::parse(\"alt-enter\").unwrap(),\n    KeyEvent::new(KeyCode::Enter, KeyModifiers::ALT),\n);\nassert_eq!(\n    crokey::parse(\"shift-F6\").unwrap(),\n    KeyEvent::new(KeyCode::F(6), KeyModifiers::SHIFT),\n);\n```\n\n## Use key combination \"literals\" thanks to procedural macros\n\nThose key combinations are parsed at compile time and have zero runtime cost.\n\nThey're efficient and convenient for matching events or defining hardcoded keybindings.\n\n```rust\nmatch key_event.into() {\n    key!(ctrl-c) =\u003e {\n        println!(\"Arg! You savagely killed me with a {}\", fmt.to_string(key_event).red());\n        break;\n    }\n    key!(ctrl-q) =\u003e {\n        println!(\"You typed {} which gracefully quits\", fmt.to_string(key_event).green());\n        break;\n    }\n    _ =\u003e {\n        println!(\"You typed {}\", fmt.to_string(key_event).blue());\n    }\n}\n```\n\nComplete example in `/examples/print_key`:\n\n![print_key](doc/print_key.png)\n\nThe `key!` macro can be called in const contexts:\n\n```rust\nconst quit: KeyCombination = key!(ctrl-q);\n```\n\n## Display a string with a configurable format\n\n```rust\nuse crokey::*;\nuse crossterm::event::{KeyCode, KeyEvent, KeyModifiers};\n\n// The default format\nlet format = KeyCombinationFormat::default();\nassert_eq!(format.to_string(key!(shift-a)), \"Shift-a\");\nassert_eq!(format.to_string(key!(ctrl-c)), \"Ctrl-c\");\n\n// A more compact format\nlet format = KeyCombinationFormat::default()\n    .with_implicit_shift()\n    .with_control(\"^\");\nassert_eq!(format.to_string(key!(shift-a)), \"A\");\nassert_eq!(format.to_string(key!(ctrl-c)), \"^c\");\n```\n\n## Deserialize keybindings using Serde\n\nWith the \"serde\" feature enabled, you can read configuration files in a direct way:\n\n```\nuse {\n    crokey::*,\n    crossterm::event::KeyEvent,\n    serde::Deserialize,\n    std::collections::HashMap,\n};\n#[derive(Debug, Deserialize)]\nstruct Config {\n    keybindings: HashMap\u003cKeyCombination, String\u003e,\n}\nstatic CONFIG_HJSON: \u0026str = r#\"\n{\n    keybindings: {\n        a: aardvark\n        shift-b: babirussa\n        ctrl-k: koala\n        alt-j: jaguar\n    }\n}\n\"#;\nlet config: Config = deser_hjson::from_str(CONFIG_HJSON).unwrap();\nlet key: KeyCombination = key!(shift-b);\nassert_eq!(\n    config.keybindings.get(\u0026key).unwrap(),\n    \"babirussa\",\n);\n```\n\nYou can use any Serde compatible format such as JSON or TOML.\n\n\n## Crossterm Compatibility\n\nCrokey includes and reexports Crossterm, so you don't have to import it and to avoid conflicts.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanop%2Fcrokey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcanop%2Fcrokey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanop%2Fcrokey/lists"}