| Crates.io | ratatui-cfg |
| lib.rs | ratatui-cfg |
| version | 0.1.1 |
| created_at | 2025-11-09 22:24:17.600175+00 |
| updated_at | 2025-11-09 22:28:03.105296+00 |
| description | A settings menu generator for Ratatui |
| homepage | https://github.com/TheBearodactyl/ratatui-cfg |
| repository | https://github.com/TheBearodactyl/ratatui-cfg |
| max_upload_size | |
| id | 1924531 |
| size | 67,817 |
A crate that lets you automatically create a settings menu based on any serializable/deserializable struct
use ratatui_cfg::{ConfigMenuTrait, MenuController, render_menu};
use ratatui_cfg_derive::ConfigMenu;
use ratatui::crossterm::event::{self, Event, KeyCode, KeyEventKind};
use serde::{Serialize, Deserialize};
use std::io;
#[derive(Debug, Clone, Serialize, Deserialize, ConfigMenu)]
struct Config {
volume: u32,
fullscreen: bool,
max_fps: u32,
}
fn main() -> io::Result<()> {
let mut terminal = ratatui::init();
let config = Config {
volume: 80,
fullscreen: false,
max_fps: 60,
};
let mut controller = MenuController::new(config);
let result = run(&mut terminal, &mut controller);
ratatui::restore();
result
}
fn run(
terminal: &mut ratatui::DefaultTerminal,
controller: &mut MenuController,
) -> io::Result {
loop {
terminal.draw(|frame| {
render_menu(frame, controller, frame.area());
})?;
if let Event::Key(key) = event::read()? {
if key.kind != KeyEventKind::Press {
continue;
}
match key.code {
KeyCode::Char('q') => break,
KeyCode::Up => controller.menu_state.previous(),
KeyCode::Down => controller.menu_state.next(),
KeyCode::Enter => {
if controller.is_current_boolean() {
controller.toggle_boolean()?;
} else if controller.is_current_submenu() {
controller.enter_submenu()?;
} else {
controller.start_editing();
}
}
KeyCode::Esc => {
if controller.editing_mode {
controller.cancel_editing();
} else if controller.menu_state.can_go_back() {
controller.menu_state.go_back();
}
}
KeyCode::Char('s') => {
controller.save_to_file("config.toml")?;
}
KeyCode::Char('r') => {
*controller = MenuController::load_from_file("config.toml")?;
}
KeyCode::Char(c) if controller.editing_mode => {
controller.handle_edit_input(c);
}
KeyCode::Backspace if controller.editing_mode => {
controller.handle_backspace();
}
KeyCode::Delete if controller.editing_mode => {
controller.handle_delete();
}
KeyCode::Left if controller.editing_mode => {
controller.move_cursor_left();
}
KeyCode::Right if controller.editing_mode => {
controller.move_cursor_right();
}
_ => {}
}
}
}
Ok(())
}
The default key bindings in the menu system are:
| Key | Action |
|---|---|
| Up/Down | Navigate menu items |
| Enter | Toggle boolean / Edit field / Enter submenu |
| Esc | Cancel editing / Go back to parent menu |
| s | Save configuration to file |
| r | Reload configuration from file |
| q | Quit application |
During text editing:
The menu UI consists of four sections:
Supported field types:
bool, i8-i128, u8-u128, f32, f64, String, usize, isizeOption<T>, Vec<T>ConfigMenuTraitYour configuration types must implement:
DebugCloneSerialize (serde)Deserialize (serde)ConfigMenuTrait (via #[derive(ConfigMenu)])