Fix bugs and improve robustness across the codebase
- Fix staged files being silently cleared when commit uses inline files - Refactor step navigation to use direct go_to_step instead of fragile delta math - Change step numbers from i32 to u32 (reject negative values at parse time) - Add tour rm command to mark files for removal during carry-forward - Add tour reset command to clear session and remove tracked files - Consolidate duplicate recursive copy functions into shared copy_tree in utils - Validate step directories are sequential (detect corruption) - Detect binary files in diffs instead of showing garbage - Use /// doc comments on enum variants so clap generates proper help text - Remove custom Help subcommand in favor of clap's built-in --help - Add CorruptedTour error variant for integrity checks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
109
src/main.rs
109
src/main.rs
@@ -1,5 +1,4 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod add;
|
||||
@@ -8,14 +7,19 @@ mod end;
|
||||
mod error;
|
||||
mod info;
|
||||
mod init;
|
||||
mod list;
|
||||
mod reset;
|
||||
mod rm;
|
||||
mod status;
|
||||
mod step;
|
||||
mod unstage;
|
||||
mod utils;
|
||||
|
||||
const TOUR_DIR: &str = "./.tour";
|
||||
const SESSION_PATH: &str = "./.tour/session";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None, disable_help_subcommand = true)]
|
||||
#[command(author, version, about = "Create and navigate code tutorials as a series of snapshots", arg_required_else_help = true)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
@@ -23,15 +27,20 @@ struct Args {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
// Create a new tour
|
||||
/// Set up a new tour in the current directory
|
||||
Init,
|
||||
|
||||
// Stage files for the next commit
|
||||
/// Stage files for the next commit
|
||||
Add {
|
||||
files: Vec<PathBuf>,
|
||||
},
|
||||
|
||||
// Add steps to the tour
|
||||
/// Remove files from staging
|
||||
Unstage {
|
||||
files: Vec<PathBuf>,
|
||||
},
|
||||
|
||||
/// Commit staged files as a new step
|
||||
Commit {
|
||||
files: Vec<PathBuf>,
|
||||
|
||||
@@ -39,76 +48,72 @@ enum Commands {
|
||||
message: String,
|
||||
},
|
||||
|
||||
// Finish the tour
|
||||
/// Mark files for removal in the next commit
|
||||
Rm {
|
||||
files: Vec<PathBuf>,
|
||||
},
|
||||
|
||||
/// Finalise the tour
|
||||
End {
|
||||
#[arg(short, long, value_name = "MESSAGE")]
|
||||
message: String,
|
||||
},
|
||||
|
||||
// Go to next step of tour
|
||||
/// Advance n steps (default 1)
|
||||
Next {
|
||||
#[arg(short, value_name = "NUM STEPS")]
|
||||
n: Option<i32>,
|
||||
n: Option<u32>,
|
||||
},
|
||||
|
||||
// Go to previous step of tour
|
||||
/// Go back n steps (default 1)
|
||||
Prev {
|
||||
#[arg(short, value_name = "NUM STEPS")]
|
||||
n: Option<i32>,
|
||||
n: Option<u32>,
|
||||
},
|
||||
|
||||
// Go to a specific step of tour
|
||||
/// Jump to step n
|
||||
Step {
|
||||
#[arg(value_name = "STEP")]
|
||||
n: i32,
|
||||
n: u32,
|
||||
},
|
||||
|
||||
// Go to beginning of tour
|
||||
/// Load the first step
|
||||
Start,
|
||||
|
||||
/// Show tour metadata
|
||||
Info,
|
||||
|
||||
// Show help
|
||||
Help,
|
||||
/// Show current step and staged files
|
||||
Status,
|
||||
|
||||
/// List all steps with messages
|
||||
List,
|
||||
|
||||
/// Reset tour session and remove tracked files
|
||||
Reset,
|
||||
}
|
||||
|
||||
fn help() {
|
||||
println!(
|
||||
"\
|
||||
\x1b[1mtour\x1b[0m — create and navigate code tutorials as a series of snapshots
|
||||
|
||||
\x1b[1mAUTHOR WORKFLOW\x1b[0m
|
||||
tour init Set up a new tour in the current directory
|
||||
tour add <files...> Stage files for the next commit
|
||||
tour commit [-m <msg>] Commit staged files as a new step
|
||||
tour commit <files...> -m <msg> Stage and commit files in one step
|
||||
tour end -m <msg> Finalise the tour
|
||||
|
||||
\x1b[1mREADER WORKFLOW\x1b[0m
|
||||
tour start Load the first step
|
||||
tour next [n] Advance n steps (default 1)
|
||||
tour prev [n] Go back n steps (default 1)
|
||||
tour step <n> Jump to step n
|
||||
|
||||
\x1b[1mOTHER\x1b[0m
|
||||
tour info Show tour metadata
|
||||
tour help Show this help message"
|
||||
);
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
match args.command {
|
||||
Some(Commands::Init) => crate::init::init()?,
|
||||
Some(Commands::Add { files }) => crate::add::add(files)?,
|
||||
Some(Commands::Commit { files, message }) => crate::commit::commit(files, message)?,
|
||||
Some(Commands::End { message }) => crate::end::end(message)?,
|
||||
Some(Commands::Next { n }) => crate::step::next(n)?,
|
||||
Some(Commands::Prev { n }) => crate::step::prev(n)?,
|
||||
Some(Commands::Step { n }) => crate::step::step_n(n)?,
|
||||
Some(Commands::Start) => crate::step::step_n(0)?,
|
||||
Some(Commands::Info) => crate::info::info()?,
|
||||
Some(Commands::Help) | None => help(),
|
||||
let result = match args.command {
|
||||
Some(Commands::Init) => crate::init::init(),
|
||||
Some(Commands::Add { files }) => crate::add::add(files),
|
||||
Some(Commands::Unstage { files }) => crate::unstage::unstage(files),
|
||||
Some(Commands::Commit { files, message }) => crate::commit::commit(files, message),
|
||||
Some(Commands::Rm { files }) => crate::rm::rm(files),
|
||||
Some(Commands::End { message }) => crate::end::end(message),
|
||||
Some(Commands::Next { n }) => crate::step::next(n),
|
||||
Some(Commands::Prev { n }) => crate::step::prev(n),
|
||||
Some(Commands::Step { n }) => crate::step::step_n(n),
|
||||
Some(Commands::Start) => crate::step::step_n(1),
|
||||
Some(Commands::Info) => crate::info::info(),
|
||||
Some(Commands::Status) => crate::status::status(),
|
||||
Some(Commands::List) => crate::list::list(),
|
||||
Some(Commands::Reset) => crate::reset::reset(),
|
||||
None => Ok(()),
|
||||
};
|
||||
if let Err(e) = result {
|
||||
eprintln!("Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user