Cleanup pass: --help, in-app help, post-rebuild message, unmodified-temp cleanup

Four post-Iteration-4 polish items surfaced by manual testing.

1. `--help` / `-h` CLI flag prints a usage banner (options +
   app-level commands + DSL grammar reference) and exits. Parse
   errors also print the banner to stderr.

2. `help` app-level command notes the same list of supported
   commands to the output panel -- a simple stand-in for the
   richer H3 help system, kept in sync with what's actually
   wired up.

3. The silent rebuild that runs when playground.db is missing
   now surfaces a system message in the output panel ("[ok]
   rebuild -- N tables, M rows reconstructed; ...") via a new
   initial_events plumbing. The user no longer wonders whether
   the .db was magically restored or whether anything happened
   on launch.

4. Unmodified empty temp projects (kind=Temp, project.yaml has
   tables: [] and relationships: []) are now auto-deleted when
   the user switches away (load / new / save as) or quits. This
   addresses the "launch app, load existing project, quit"
   pattern that was leaving an empty temp directory behind
   every time. Modified temps (with any user-created tables or
   relationships) are never auto-deleted; corrupted projects
   are also never auto-deleted (defensive default-to-false on
   yaml read/parse errors).

Tests: 338 passing (272 lib + 9 + 5 + 6 + 20 + 9 + 17),
0 failing, 0 skipped. Clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-08 06:43:49 +00:00
parent f2198275f0
commit b7addd6161
6 changed files with 302 additions and 18 deletions
+54
View File
@@ -20,8 +20,45 @@ pub struct Args {
/// this path (L1, ADR-0015 §1). Mutually exclusive with
/// `--resume` once that lands.
pub project_path: Option<PathBuf>,
/// `--help` / `-h`: print usage to stdout and exit. The
/// runtime checks this flag before doing any other work.
pub help: bool,
}
/// Usage banner printed by `--help`. Kept as one block so the
/// formatting is reviewable on its own.
pub const HELP_TEXT: &str = "\
rdbms-playground — a TUI playground for relational database concepts
Usage:
rdbms-playground [options] [<project-path>]
Arguments:
<project-path> Path to an existing project directory.
Without this, a fresh auto-named temp
project is created in the data dir.
Options:
-h, --help Print this help and exit.
--theme <light|dark> Override theme (default: auto-detect).
--data-dir <PATH> Use PATH as the data root instead of
the OS-standard location for this run.
--log-file <PATH> Write tracing output to PATH.
App-level commands (typed inside the app, available in both modes):
quit / q Exit cleanly.
mode simple|advanced Switch input mode.
help Show this list of commands in-app.
save Save the current temp project under a
chosen name (or `save as` to copy a
named project to a new location).
save as Always prompt for a target name/path.
new Close current, create a fresh temp.
load Open the project picker.
rebuild Rebuild playground.db from project.yaml
+ data/, with confirmation.
";
#[derive(Debug, thiserror::Error)]
pub enum ArgsError {
#[error("missing value for --{0}")]
@@ -54,9 +91,13 @@ impl Args {
let mut log_path = env::var_os("RDBMS_PLAYGROUND_LOG_FILE").map(PathBuf::from);
let mut data_dir: Option<PathBuf> = None;
let mut project_path: Option<PathBuf> = None;
let mut help = false;
let mut iter = iter.into_iter().map(Into::into);
while let Some(arg) = iter.next() {
match arg.as_str() {
"--help" | "-h" => {
help = true;
}
"--theme" => {
let value = iter.next().ok_or(ArgsError::MissingValue("theme"))?;
theme = match value.as_str() {
@@ -98,6 +139,7 @@ impl Args {
log_path,
data_dir,
project_path,
help,
})
}
}
@@ -203,6 +245,18 @@ mod tests {
assert!(matches!(err, ArgsError::MultiplePaths { .. }), "got: {err:?}");
}
#[test]
fn help_flag_long_form_sets_help() {
let args = Args::parse(["--help"]).unwrap();
assert!(args.help);
}
#[test]
fn help_flag_short_form_sets_help() {
let args = Args::parse(["-h"]).unwrap();
assert!(args.help);
}
#[test]
fn unknown_double_dash_flag_errors_even_with_positional() {
// Make sure the path-vs-flag distinction is robust: