Compare commits
4 Commits
507c61fe5f
...
aced95a845
| Author | SHA1 | Date | |
|---|---|---|---|
| aced95a845 | |||
| e648b86c93 | |||
| aafc847d02 | |||
| 1eda5a9642 |
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 } => {
|
||||
|
||||
@@ -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(())
|
||||
|
||||
25
src/step.rs
25
src/step.rs
@@ -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 {
|
||||
|
||||
11
src/utils.rs
11
src/utils.rs
@@ -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()
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user