Skip to content

feat: Add recipes/keybind - #1008

Open
yanganto wants to merge 14 commits into
ratatui:mainfrom
yanganto:keybind
Open

feat: Add recipes/keybind#1008
yanganto wants to merge 14 commits into
ratatui:mainfrom
yanganto:keybind

Conversation

@yanganto

Copy link
Copy Markdown

No description provided.

@joshka

joshka commented Dec 14, 2025

Copy link
Copy Markdown
Member

Thanks for putting this together. Configurable keybindings are absolutely a real problem people run into, and I think this is a good topic for the website 👍

I think there may be a bit of scope confusion coming from the earlier discussion, so I want to clarify intent rather than push back on the idea itself.

On the Ratatui website, a recipe is meant to document how to approach solving a problem in an existing app, not to prescribe a single starting template. The goal is to help readers understand the shape of the solution, the trade-offs involved, and how to integrate it into code they already have.

In this case, the recipe should focus on:

  • How to structure keybinding logic in an existing Ratatui app
  • How to keep bindings maintainable and extensible over time
  • How to support user configuration and evolution of bindings
  • What patterns tend to work well (enums, action layers, matching, config loading, etc.)

Your crossterm-keybind crate and template are a perfectly valid approach to this, but they should be presented as one concrete implementation rather than the foundation of the recipe itself. Ideally, the narrative explains the general approach first, then shows how your library fits that model and what it buys you.

More generally, recipes on the Ratatui site work best when they are written as guidance rather than prescriptions. They should assume readers already have an application and are looking to improve it. Explaining design goals, common patterns, and trade-offs up front helps keep the content broadly useful and avoids implying that there is a single correct architecture.

As a rough guide, a structure that usually works well for recipes is something like:

  • Problem statement and motivation
  • Design goals and constraints
  • Core pattern or approach
  • Handling input and wiring it into application logic
  • Supporting user configuration
  • One concrete implementation example
  • Optional extras, such as a starter template

I think the template works best as a nice to have at the end, along the lines of:

“If you want a ready-made starting point that applies these ideas, here’s a template that puts it all together.”

That keeps the recipe broadly useful, avoids locking readers into a single solution, and aligns with the overall tone of the Ratatui docs: practical guidance first, tools second.

Overall, the topic is solid, the motivation is good, and I think with a small reframing this could be a really strong addition to the recipes section.

* refact with recipe style

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
@yanganto

Copy link
Copy Markdown
Author

Hi @joshka
Thanks for your suggestion. I fix the content, please take a look at it again. 🙏

@orhun

orhun commented Dec 15, 2025

Copy link
Copy Markdown
Member

It seems to me that crossterm-keybind is still being presented as "the thing that you should use to do this" instead of "one of the things that you can use to do this" in the recipe. We should generalize the text a bit and probably touch on the other solutions as well before we reach to the code examples using crossterm-keybind. (we might also leave out the code examples for the crate and just reference to it with a link)

@yanganto

yanganto commented Dec 15, 2025

Copy link
Copy Markdown
Author

There will be a lot of possible ways to handle keybindings. If a user has a strong and clear idea about how to implement it, he will not use a crate to build it, and will do it with raw key events. These are the current ways.

There are no words about right or wrong. I just provide a solution to help people if they do not have an idea, but want a way to avoid problems, and this is the majority. Most people build a tui for business task, they will not be happy to play with keybindings. I saw the pain point. (You never know how many times I say bad words when I push code, but the git tool upgraded again, and I temporarily can not use it, before I learn more what is new in the config. I do not check every config after I did all system upgraded, and I use nixOS in a roll release way, I believe the Arch user will run into the same problems) This is MIT license, I do this and will happy to use more Rust tui applications and see the ecosystem blooming. I am not native English/Romance languages speaker, I already tried AI to prevent issues. If my words is less, people will ask me to describe more, else they don't know the solution. If my words too much, people will like to think I force people should do this.

As you can see, you can disable the derive feature, or just use struct-patch or toml-example to have part of the idea. Also, the crossterm-keybind-core is decoupled and easy to use in different usage. I am open minded, and already acept that developers to use everything in different way. If you take a deep look at the struct-patch people use different design patterns on patches and open PR or issue to me. I always open my mind and fulfill functions for different way. If there is no other real user request/issue to me. For now, I do not think I should go deep and provide another show case of crossterm-keybind-core to build up another design pattern and solution for the problems, and I am not really in use. And it is weird for me to list down something I not really in use.

Overall, if you think some other specific design pattern for the keybinding, or highlight others' work I am happy to add a section to do. The problem for me is should I list down the solution I never used? (Did a PR for tokio template should included async-std template at the same time?) I will be open mide and will not against it if other crate builder edit the page and want add any section about this topic in the future? Back to the topic, I want a solution to over the keybinding issues and roll out TUI application in quick and saving the developer power, let is why we do open source. Isn't it?

* add descriptions about keybind-rs

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
@yanganto

yanganto commented Dec 16, 2025

Copy link
Copy Markdown
Author

I did not noticed there is a really similar solution keybind-rs in the same idea using an enum for keybind. I just add the other crate information there. If you think there is still something I should add into the docs, please point out directly. That will easilier for me. Thank you.

yanganto and others added 2 commits December 16, 2025 11:01
* update docs for crossterm-keybind 0.2

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
Comment thread src/content/docs/recipes/apps/keybind.md Outdated
* add from scratch section

---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
@yanganto

yanganto commented Dec 17, 2025

Copy link
Copy Markdown
Author

Hi @orhun
How do you think about the From Scratch section? In this section developer will has an idea how to do it. And in this section, there is no word about which format of the configure file or using mod/struct/enum will be the best practice. With this clue, developer potentially can complete the feature with 0-dependency.

After they have more idea, they can see the configurable keybinding feature is much about building a parser for a config file. Normally, this is not a task align their business, and also they can use crate not in a blind using. If you still think we need more sections in this recipe, please let me know. I am looking forward and will actively response.

@orhun

orhun commented Dec 17, 2025

Copy link
Copy Markdown
Member

Yeah that's better. I wish we could give code examples for that also.

I still think that we are spending quite a large amount of time explaining concepts with references to 3rd party libs.

yanganto and others added 2 commits December 18, 2025 11:39
* add pesudo code and trim 3rd party codes

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
@yanganto

Copy link
Copy Markdown
Author

Hi @orhun
I believe the current content is good to go. Thanks for advice.

@orhun
orhun requested a review from joshka December 18, 2025 18:38
@yanganto

Copy link
Copy Markdown
Author

Hi @joshka
Looking forward to hear from you. Thank you.

@joshka

joshka commented Dec 21, 2025

Copy link
Copy Markdown
Member

Hi there, I want to give you a good response on this, but it might be a bit delayed.

If you want to get ahead of me on this, there's a bunch of background reading that would be worth brushing up on at ratatui/ratatui#627

Some quick off the shallow review points:

  • It still reads a bit disconnected from ratatui in the problem setup (e.g. show me where in an app's flow this problem happens, talk about the setup, configuration, and runtime in a connected / grounded way (i.e. fn run() { ... let event = ...; let action = action_from_key }. This helps people orient / ground themselves against the problem a bit more
  • It still seems like a way to jump into your library / solution rather than thinking about what the simplest form of keybinding looks like (either an array / map or a match statement). E.g.: (with some small helper methods):
const BINDINGS: &[Binding] = &[
    key(KeyCode::Up, Action::MoveUp),
    key(KeyCode::Char('k'), Action::MoveUp),
    key(KeyCode::Down, Action::MoveDown),
    key(KeyCode::Char('j'), Action::MoveDown),
    key(KeyCode::Left, Action::MoveLeft),
    key(KeyCode::Char('h'), Action::MoveLeft),
    key(KeyCode::Right, Action::MoveRight),
    key(KeyCode::Char('l'), Action::MoveRight),
    ctrl(KeyCode::Char('s'), Action::Save),
    key(KeyCode::Char('?'), Action::Help),
    shift(KeyCode::Char('h'), Action::Help),
    key(KeyCode::Esc, Action::Quit),
    key(KeyCode::Char('q'), Action::Quit),
    ctrl(KeyCode::Char('c'), Action::Quit),
];

fn action_for_key(event: KeyEvent) -> Option<Action> {
    let event = event.as_key_press_event()?;

    BINDINGS.iter().find_map(|binding| {
        (event.code == binding.code && event.modifiers == binding.modifiers)
            .then_some(binding.action)
    })
}

A similar approach using a match statement would work.

I also asked GPT-5.2 to review the article and it generated a pretty decent review. I don't know what your thoughts are on AI tooling, but if it's something that you don't mind, I'd recommend reading https://chatgpt.com/share/694763ed-4880-8010-a30b-beacd292d778

Side note:
There's probably lots of little things that could also be implemented in crossterm to support keybinding a bit better (e.g. implementing FromStr on KeyEvent makes writing config easier, handling comparisons against KeyCode directly instead of PartialEq on KeyEvent is also an idea there).

* revisit with ChatGPT 5.1 suggestions

 https://chatgpt.com/share/694763ed-4880-8010-a30b-beacd292d778

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yanganto <10803111+yanganto@users.noreply.github.com>
@yanganto

yanganto commented Dec 22, 2025

Copy link
Copy Markdown
Author

Hi @joshka
Thanks your review, I am appreciate your time. If this can really move forward and easier for you to merge it, or if this your standard way for every PR. I am always happy to do so, no mater it is from AI or not. However, it is still important that we should not keep loop here, human time is precious. (These PR from template and from websites take more than triple times to build a crate for this) You can asking AI to review for many times, and there will always something comes out. If we play on this for years and wasting computing power, but nothing really good for human. Besides, there will not be any alignment with spirit of open source.

Some suggestion from AI are opposite with previous review, tradeoffs is much subjective thing and no meaning because different user has different using case, so I always focus on what solutions can use now.

In a few places the text sounds slightly defensive (e.g. “we are not saying this is best practice”). You could confidently state these as options and tradeoffs without apologizing for them.

Please kindly noted things you are talking and comparing are a discussion and implemented codes from people's work.

Please kindly think again your previous helper functions shown any related thing with the title, Configurable Keybindings, of the article, or with any additional features are shown in current implementation.

  • Multiple Shortcuts
  • Backward Compatibility
  • Maintainability(keep config with document updated)
  • Better Developer Experience(default keybinds)
  • Flexible Keybindings(trigger multiple event token from one keybinding.)
  • Keybind Hint
  • Working with Embedded Config
  • Customizable Deserialization
  • Emacs-style

There are already crates with working code over abstract discussion or promises, because Linus Torvalds says, "Show me the code". Could you open mind and accept people use the ratatui with different crates and in different way? At least author of keybind-rs and me are using a enum way for this, more important the article is neutral.

Furthermore, I will be happy if you want me to review others work in the future, just @. For now, I believe this PR is good to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants