feat: persist & restore per-project input mode (#14)
The input mode always started in simple; a learner who quit in advanced had to re-toggle every launch. Store the mode per-project in project.yaml (project.mode:, optional, default simple) and restore it on every open. Mode is live UI state, not schema: the worker stamps the current mode into project.yaml on every write, so a later command rewrites the live value rather than clobbering it — no db round-trip needed. The mode is persisted on unload (quit + project switch) so the mode you leave a project in is always what reopens; the `mode` command also persists immediately. A switch saves the outgoing mode, then restores the incoming project's stored mode. New --mode simple|advanced CLI flag (precedence --mode > stored > simple; combines with --resume). A teacher can ship a project that opens in advanced mode and export it to students (the mode travels in the zip). ADR-0015 Amendment 1; ADR-0003 note; help banner; requirements L1b.
This commit is contained in:
+55
-1
@@ -736,6 +736,7 @@ impl App {
|
||||
display_name,
|
||||
is_temp,
|
||||
history_entries,
|
||||
mode,
|
||||
} => {
|
||||
self.note_system(crate::t!(
|
||||
"project.switched_ok",
|
||||
@@ -746,6 +747,9 @@ impl App {
|
||||
self.tables.clear();
|
||||
self.current_table = None;
|
||||
self.seed_history(history_entries);
|
||||
// Restore the switched-to project's stored input
|
||||
// mode (ADR-0015 mode-restore amendment, issue #14).
|
||||
self.mode = mode;
|
||||
Vec::new()
|
||||
}
|
||||
AppEvent::ProjectSwitchFailed { error } => {
|
||||
@@ -1311,7 +1315,9 @@ impl App {
|
||||
ModeValue::Advanced => "advanced",
|
||||
};
|
||||
self.handle_mode_command(&format!("mode {arg}"));
|
||||
Vec::new()
|
||||
// Persist the new mode so it is restored on the next
|
||||
// open (ADR-0015 mode-restore amendment, issue #14).
|
||||
vec![Action::PersistMode(self.mode)]
|
||||
}
|
||||
AppCommand::Messages { value } => {
|
||||
let raw = match value {
|
||||
@@ -2906,6 +2912,54 @@ mod tests {
|
||||
assert!(!app.output.is_empty());
|
||||
}
|
||||
|
||||
// ---- ADR-0015 mode-restore amendment (issue #14) ----
|
||||
|
||||
#[test]
|
||||
fn mode_command_changes_mode_and_emits_persist_action() {
|
||||
// The `mode` command flips the live mode AND emits
|
||||
// `PersistMode` so the runtime records it to project.yaml.
|
||||
let mut app = App::new();
|
||||
app.mode = Mode::Advanced;
|
||||
type_str(&mut app, "mode simple");
|
||||
let actions = submit(&mut app);
|
||||
assert_eq!(app.mode, Mode::Simple, "live mode flipped");
|
||||
assert_eq!(
|
||||
actions,
|
||||
vec![Action::PersistMode(Mode::Simple)],
|
||||
"the mode change is persisted",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mode_command_via_one_shot_escape_persists_advanced() {
|
||||
// Reaching `mode advanced` from simple via the `:` one-shot
|
||||
// (ADR-0003) still emits the persist action for advanced.
|
||||
let mut app = App::new();
|
||||
assert_eq!(app.mode, Mode::Simple);
|
||||
type_str(&mut app, ":mode advanced");
|
||||
let actions = submit(&mut app);
|
||||
assert_eq!(app.mode, Mode::Advanced);
|
||||
assert!(
|
||||
actions.contains(&Action::PersistMode(Mode::Advanced)),
|
||||
"expected PersistMode(Advanced), got {actions:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_switched_event_restores_the_stored_mode() {
|
||||
// A switch carries the target project's stored mode; the
|
||||
// App adopts it ("loading triggers the mode switch").
|
||||
let mut app = App::new();
|
||||
assert_eq!(app.mode, Mode::Simple);
|
||||
app.update(AppEvent::ProjectSwitched {
|
||||
display_name: "Other".to_string(),
|
||||
is_temp: false,
|
||||
history_entries: Vec::new(),
|
||||
mode: Mode::Advanced,
|
||||
});
|
||||
assert_eq!(app.mode, Mode::Advanced);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bare_create_table_emits_friendly_parse_error() {
|
||||
let mut app = App::new();
|
||||
|
||||
Reference in New Issue
Block a user