use envision::prelude::*;
struct KeyHintsApp;
#[derive(Clone)]
struct State {
hints: KeyHintsState,
mode: AppMode,
}
#[derive(Clone, Debug, PartialEq)]
enum AppMode {
Normal,
Edit,
}
#[derive(Clone, Debug)]
enum Msg {
SwitchToEdit,
SwitchToNormal,
Quit,
}
fn normal_hints() -> KeyHintsState {
KeyHintsState::new()
.hint("e", "Edit")
.hint("d", "Delete")
.hint("/", "Search")
.hint("?", "Help")
.hint("q", "Quit")
}
fn edit_hints() -> KeyHintsState {
KeyHintsState::new()
.hint("Esc", "Cancel")
.hint("Ctrl+S", "Save")
.hint("Tab", "Next field")
.hint("Shift+Tab", "Prev field")
}
impl App for KeyHintsApp {
type State = State;
type Message = Msg;
fn init() -> (State, Command<Msg>) {
let state = State {
hints: normal_hints(),
mode: AppMode::Normal,
};
(state, Command::none())
}
fn update(state: &mut State, msg: Msg) -> Command<Msg> {
match msg {
Msg::SwitchToEdit => {
state.mode = AppMode::Edit;
state.hints = edit_hints();
}
Msg::SwitchToNormal => {
state.mode = AppMode::Normal;
state.hints = normal_hints();
}
Msg::Quit => return Command::quit(),
}
Command::none()
}
fn view(state: &State, frame: &mut Frame) {
let theme = Theme::default();
let area = frame.area();
let chunks = Layout::vertical([Constraint::Min(0), Constraint::Length(1)]).split(area);
let mode_label = match state.mode {
AppMode::Normal => "NORMAL",
AppMode::Edit => "EDIT",
};
let content = format!(
"Current mode: {}\n\nPress 'e' to switch to edit mode.\nPress Esc to return to normal mode.\nPress 'q' to quit.",
mode_label
);
let widget = ratatui::widgets::Paragraph::new(content).block(
ratatui::widgets::Block::default()
.borders(ratatui::widgets::Borders::ALL)
.title("Application"),
);
frame.render_widget(widget, chunks[0]);
KeyHints::view(
&state.hints,
frame,
chunks[1],
&theme,
&ViewContext::default(),
);
}
fn handle_event(event: &Event) -> Option<Msg> {
if let Some(key) = event.as_key() {
match key.code {
KeyCode::Char('q') => Some(Msg::Quit),
KeyCode::Char('e') => Some(Msg::SwitchToEdit),
KeyCode::Esc => Some(Msg::SwitchToNormal),
_ => None,
}
} else {
None
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut vt = Runtime::<KeyHintsApp, _>::virtual_terminal(70, 10)?;
println!("=== KeyHints Example ===\n");
vt.tick()?;
println!("Normal mode (with navigation hints):");
println!("{}\n", vt.display());
vt.dispatch(Msg::SwitchToEdit);
vt.tick()?;
println!("Edit mode (different hints):");
println!("{}\n", vt.display());
vt.dispatch(Msg::SwitchToNormal);
vt.tick()?;
println!("Back to normal mode:");
println!("{}\n", vt.display());
Ok(())
}