feat(tui): add onboarding tutorial with :tutorial command and first‑run UI
- Introduce `show_onboarding` UI setting (default true) and persist its state after first launch. - Show onboarding status line and system status on initial run; fallback to normal status thereafter. - Implement `show_tutorial` method displaying keybinding tips and system status. - Register `:tutorial` command in command palette. - Add migration documentation explaining `schema_version` update and deprecation of `agent.max_tool_calls`. - Update README with description of the new tutorial command.
This commit is contained in:
@@ -20,6 +20,13 @@ use crate::events::Event;
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
const ONBOARDING_STATUS_LINE: &str =
|
||||
"Welcome to Owlen! Press F1 for help or type :tutorial for keybinding tips.";
|
||||
const ONBOARDING_SYSTEM_STATUS: &str = "Normal ▸ h/j/k/l • Insert ▸ i,a • Visual ▸ v • Command ▸ :";
|
||||
const TUTORIAL_STATUS: &str = "Tutorial loaded. Review quick tips in the footer.";
|
||||
const TUTORIAL_SYSTEM_STATUS: &str =
|
||||
"Normal ▸ h/j/k/l • Insert ▸ i,a • Visual ▸ v • Command ▸ : • Send ▸ Enter";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ModelSelectorItem {
|
||||
kind: ModelSelectorItemKind,
|
||||
@@ -202,6 +209,7 @@ impl ChatApp {
|
||||
let config_guard = controller.config_async().await;
|
||||
let theme_name = config_guard.ui.theme.clone();
|
||||
let current_provider = config_guard.general.default_provider.clone();
|
||||
let show_onboarding = config_guard.ui.show_onboarding;
|
||||
drop(config_guard);
|
||||
let theme = owlen_core::theme::get_theme(&theme_name).unwrap_or_else(|| {
|
||||
eprintln!("Warning: Theme '{}' not found, using default", theme_name);
|
||||
@@ -211,7 +219,11 @@ impl ChatApp {
|
||||
let app = Self {
|
||||
controller,
|
||||
mode: InputMode::Normal,
|
||||
status: "Normal mode • Press F1 for help".to_string(),
|
||||
status: if show_onboarding {
|
||||
ONBOARDING_STATUS_LINE.to_string()
|
||||
} else {
|
||||
"Normal mode • Press F1 for help".to_string()
|
||||
},
|
||||
error: None,
|
||||
models: Vec::new(),
|
||||
available_providers: Vec::new(),
|
||||
@@ -252,13 +264,27 @@ impl ChatApp {
|
||||
available_themes: Vec::new(),
|
||||
selected_theme_index: 0,
|
||||
pending_consent: None,
|
||||
system_status: String::new(),
|
||||
system_status: if show_onboarding {
|
||||
ONBOARDING_SYSTEM_STATUS.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
_execution_budget: 50,
|
||||
agent_mode: false,
|
||||
agent_running: false,
|
||||
operating_mode: owlen_core::mode::Mode::default(),
|
||||
};
|
||||
|
||||
if show_onboarding {
|
||||
let mut cfg = app.controller.config_mut();
|
||||
if cfg.ui.show_onboarding {
|
||||
cfg.ui.show_onboarding = false;
|
||||
if let Err(err) = config::save_config(&cfg) {
|
||||
eprintln!("Warning: Failed to persist onboarding preference: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((app, session_rx))
|
||||
}
|
||||
|
||||
@@ -402,6 +428,24 @@ impl ChatApp {
|
||||
self.system_status.clear();
|
||||
}
|
||||
|
||||
pub fn show_tutorial(&mut self) {
|
||||
self.error = None;
|
||||
self.status = TUTORIAL_STATUS.to_string();
|
||||
self.system_status = TUTORIAL_SYSTEM_STATUS.to_string();
|
||||
let tutorial_body = concat!(
|
||||
"Keybindings overview:\n",
|
||||
" • Movement: h/j/k/l, gg/G, w/b\n",
|
||||
" • Insert text: i or a (Esc to exit)\n",
|
||||
" • Visual select: v (Esc to exit)\n",
|
||||
" • Command mode: : (press Enter to run, Esc to cancel)\n",
|
||||
" • Send message: Enter in Insert mode\n",
|
||||
" • Help overlay: F1 or ?\n"
|
||||
);
|
||||
self.controller
|
||||
.conversation_mut()
|
||||
.push_system_message(tutorial_body.to_string());
|
||||
}
|
||||
|
||||
pub fn command_buffer(&self) -> &str {
|
||||
&self.command_buffer
|
||||
}
|
||||
@@ -439,6 +483,7 @@ impl ChatApp {
|
||||
("n", "Alias for new"),
|
||||
("theme", "Switch theme"),
|
||||
("themes", "List available themes"),
|
||||
("tutorial", "Show keybinding tutorial"),
|
||||
("reload", "Reload configuration and themes"),
|
||||
("e", "Edit a file"),
|
||||
("edit", "Alias for edit"),
|
||||
@@ -1688,6 +1733,9 @@ impl ChatApp {
|
||||
}
|
||||
}
|
||||
}
|
||||
"tutorial" => {
|
||||
self.show_tutorial();
|
||||
}
|
||||
"themes" => {
|
||||
// Load all themes and enter browser mode
|
||||
let themes = owlen_core::theme::load_all_themes();
|
||||
|
||||
Reference in New Issue
Block a user