adding important subcommands

This commit is contained in:
2026-03-02 21:55:37 +00:00
parent 1dea592fb2
commit c0a71bc285
4 changed files with 217 additions and 30 deletions

138
src/info.rs Normal file
View File

@@ -0,0 +1,138 @@
use std::fs;
use std::io::{self, Write};
use std::time::{SystemTime, UNIX_EPOCH};
const INFO_PATH: &str = "./.tour/info";
struct TourInfo {
author: String,
description: String,
language: String,
created: String,
updated: String,
}
impl TourInfo {
fn parse(content: &str) -> Self {
let mut author = String::new();
let mut description = String::new();
let mut language = String::new();
let mut created = String::new();
let mut updated = String::new();
for line in content.lines() {
if let Some((key, value)) = line.split_once('=') {
match key {
"author" => author = value.to_string(),
"description" => description = value.to_string(),
"language" => language = value.to_string(),
"created" => created = value.to_string(),
"updated" => updated = value.to_string(),
_ => {}
}
}
}
TourInfo { author, description, language, created, updated }
}
fn serialize(&self) -> String {
format!(
"author={}\ndescription={}\nlanguage={}\ncreated={}\nupdated={}\n",
self.author, self.description, self.language, self.created, self.updated
)
}
}
pub fn set_info() -> Result<(), io::Error> {
macro_rules! prompt {
($msg:expr) => {{
print!($msg);
io::stdout().flush()?;
let mut buf = String::new();
io::stdin().read_line(&mut buf)?;
buf.trim().to_string()
}};
}
let author = prompt!("Author: ");
let description = prompt!("Description: ");
let language = prompt!("Language: ");
let today = current_date();
let info = TourInfo {
author,
description,
language,
created: today.clone(),
updated: today,
};
fs::write(INFO_PATH, info.serialize())
}
pub fn get_info() -> Result<(), io::Error> {
let content = fs::read_to_string(INFO_PATH).map_err(|_| {
io::Error::new(
io::ErrorKind::NotFound,
"No tour info found. Run `tour init` to set up a tour.",
)
})?;
let info = TourInfo::parse(&content);
println!("Author: {}", info.author);
println!("Description: {}", info.description);
println!("Language: {}", info.language);
println!("Created: {}", info.created);
println!("Updated: {}", info.updated);
Ok(())
}
pub fn update_last_modified() -> Result<(), io::Error> {
let content = fs::read_to_string(INFO_PATH).unwrap_or_default();
let mut info = TourInfo::parse(&content);
info.updated = current_date();
fs::write(INFO_PATH, info.serialize())
}
pub fn info() -> Result<(), io::Error> {
get_info()
}
fn current_date() -> String {
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let (y, m, d) = days_to_ymd((secs / 86400) as u32);
format!("{:04}-{:02}-{:02}", y, m, d)
}
fn days_to_ymd(mut days: u32) -> (u32, u32, u32) {
let mut year = 1970u32;
loop {
let days_in_year = if is_leap(year) { 366 } else { 365 };
if days < days_in_year {
break;
}
days -= days_in_year;
year += 1;
}
let month_days = if is_leap(year) {
[31u32, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
} else {
[31u32, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
};
let mut month = 1u32;
for (i, &md) in month_days.iter().enumerate() {
if days < md {
month = i as u32 + 1;
break;
}
days -= md;
}
(year, month, days + 1)
}
fn is_leap(year: u32) -> bool {
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
}