Compare commits

..

4 Commits

Author SHA1 Message Date
aced95a845 bug fixes 2026-03-07 14:50:09 +00:00
e648b86c93 Make path not show with debug quotes 2026-03-07 14:49:28 +00:00
aafc847d02 input paths normalised before comparison 2026-03-07 14:49:02 +00:00
1eda5a9642 Missing message fix 2026-03-07 14:48:18 +00:00
5 changed files with 38 additions and 14 deletions

View File

@@ -32,11 +32,12 @@ pub fn add(files: Vec<PathBuf>) -> Result<(), TourError> {
.open(STAGED_PATH)?;
for file in &files {
if existing_set.contains(file) {
println!("already staged: {}", file.display());
let normalized: PathBuf = file.components().collect();
if existing_set.contains(&normalized) {
println!("already staged: {}", normalized.display());
} else {
writeln!(staged, "{}", file.display())?;
println!("staged: {}", file.display());
writeln!(staged, "{}", normalized.display())?;
println!("staged: {}", normalized.display());
}
}

View File

@@ -31,10 +31,10 @@ impl std::fmt::Display for TourError {
write!(f, "Cannot end a tour with no steps. Use `tour commit` to add steps first.")
}
Self::NotADescendant(p) => {
write!(f, "File {:?} is not a descendant of the working directory.", p)
write!(f, "File {} is not a descendant of the working directory.", p.display())
}
Self::InsideTourDir(p) => {
write!(f, "File {:?} is inside a .tour directory, which is not allowed.", p)
write!(f, "File {} is inside a .tour directory, which is not allowed.", p.display())
}
Self::FileNotFound(p) => write!(f, "File not found: {}", p.display()),
Self::StepOutOfRange { step, total } => {

View File

@@ -15,7 +15,8 @@ pub fn list() -> Result<(), TourError> {
for i in 0..total {
let step_dir = Path::new(TOUR_DIR).join("steps").join(i.to_string());
let message = fs::read_to_string(step_dir.join("message")).unwrap_or_default();
let message = fs::read_to_string(step_dir.join("message"))
.unwrap_or_else(|_| "(no message)".into());
println!(" {}. {}", i + 1, message.trim());
}
Ok(())

View File

@@ -59,17 +59,28 @@ fn go_to_step(target: u32, total: u32) -> Result<(), TourError> {
let tracked = get_tracked_files()?;
let old_files = snapshot_tracked_files(&cwd, &tracked)?;
remove_tracked_files(&cwd, &tracked)?;
// Copy step contents into CWD (skipping the message file)
// Stage new step files to a temp dir first — if this fails, working files are untouched
let step_dir = Path::new(TOUR_DIR).join("steps").join(target.to_string());
let tmp_dir = Path::new(TOUR_DIR).join("tmp_step");
if tmp_dir.exists() {
fs::remove_dir_all(&tmp_dir)?;
}
fs::create_dir_all(&tmp_dir)?;
for entry in fs::read_dir(&step_dir)? {
let entry = entry?;
if entry.file_name() == "message" {
continue;
}
copy_tree(&entry.path(), &tmp_dir.join(entry.file_name()))?;
}
// Now safe to remove old tracked files and install the new ones
remove_tracked_files(&cwd, &tracked)?;
for entry in fs::read_dir(&tmp_dir)? {
let entry = entry?;
copy_tree(&entry.path(), &cwd.join(entry.file_name()))?;
}
fs::remove_dir_all(&tmp_dir)?;
// Persist the new step
fs::write(SESSION_PATH, format!("STEP={}", target))?;
@@ -77,7 +88,8 @@ fn go_to_step(target: u32, total: u32) -> Result<(), TourError> {
let new_files = snapshot_tracked_files(&cwd, &tracked)?;
print_changes(&old_files, &new_files);
let message = fs::read_to_string(step_dir.join("message")).unwrap_or_default();
let message = fs::read_to_string(step_dir.join("message"))
.unwrap_or_else(|_| "(no message)".into());
println!(
"\n{BOLD}Step {}/{total}:{RESET} {}",
target + 1,
@@ -195,6 +207,11 @@ fn print_diff(old: &str, new: &str) {
let m = old_lines.len();
let n = new_lines.len();
if m > 1000 || n > 1000 {
println!(" (file changed)");
return;
}
// LCS table
let mut dp = vec![vec![0usize; n + 1]; m + 1];
for i in 1..=m {

View File

@@ -17,8 +17,8 @@ pub fn get_current_step() -> Option<u32> {
fs::read_to_string(SESSION_PATH)
.ok()
.and_then(|s| {
s.split("STEP=")
.nth(1)
s.lines()
.find_map(|l| l.strip_prefix("STEP="))
.and_then(|v| v.trim().parse::<u32>().ok())
})
}
@@ -53,7 +53,12 @@ pub fn get_tour_step() -> Result<u32, TourError> {
pub fn copy_path(src: &Path, dest_dir: &Path) -> Result<(), io::Error> {
let relative_src = if src.is_absolute() {
let cwd = std::env::current_dir()?;
src.strip_prefix(&cwd).unwrap_or(src).to_path_buf()
src.strip_prefix(&cwd)
.map_err(|_| io::Error::new(
io::ErrorKind::InvalidInput,
format!("path '{}' is not under the current directory", src.display()),
))?
.to_path_buf()
} else {
src.to_path_buf()
};