refactor(cli): consolidate output through output module
- Add header(), detail(), item(), blank() functions to output.rs
- Replace all raw println!() calls with output::* equivalents
- Fix {:?} debug format for paths — use .display() for clean output
- Extract print_tasks() helper to deduplicate task display logic
- Consistent formatting: info for empty states, item for list entries
This commit is contained in:
parent
c32a6fbe8b
commit
b863e025d5
|
|
@ -35,7 +35,7 @@ pub fn execute(path: String, name: String) -> Result<()> {
|
|||
config.save_to_file(&config_path)
|
||||
.context("Failed to save config")?;
|
||||
|
||||
output::success(&format!("Initialized workspace \"{}\" at {:?}", name, path_buf));
|
||||
output::success(&format!("Initialized workspace \"{}\" at {}", name, path_buf.display()));
|
||||
output::success("Created default list \"My Tasks\"");
|
||||
output::success(&format!("Set \"{}\" as current workspace", name));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
use anyhow::{Context, Result};
|
||||
use colored::*;
|
||||
use bevy_tasks_core::{Task, TaskStatus};
|
||||
use crate::output;
|
||||
use crate::commands::get_repository;
|
||||
|
||||
fn print_tasks(tasks: &[Task]) {
|
||||
if tasks.is_empty() {
|
||||
output::item("No tasks");
|
||||
return;
|
||||
}
|
||||
for task in tasks {
|
||||
let checkbox = if task.status == TaskStatus::Completed { "[✓]".green() } else { "[ ]".normal() };
|
||||
let due_str = task.due_date.map(|d| format!(" (due: {})", d.format("%Y-%m-%d")).yellow().to_string()).unwrap_or_default();
|
||||
output::item(&format!("{} {}{} {}", checkbox, task.title, due_str, task.id.to_string().dimmed()));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(name: String, workspace: Option<String>) -> Result<()> {
|
||||
let (mut repo, _workspace_name) = get_repository(workspace)?;
|
||||
|
||||
|
|
@ -21,7 +34,7 @@ pub fn show(list_name: Option<String>, workspace: Option<String>) -> Result<()>
|
|||
.context("Failed to get lists")?;
|
||||
|
||||
if lists.is_empty() {
|
||||
println!("No lists found. Create one with 'bevy-tasks list create <name>'");
|
||||
output::info("No lists found. Create one with 'bevy-tasks list create <name>'");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -31,54 +44,14 @@ pub fn show(list_name: Option<String>, workspace: Option<String>) -> Result<()>
|
|||
.find(|l| l.title == name)
|
||||
.ok_or_else(|| anyhow::anyhow!("List '{}' not found", name))?;
|
||||
|
||||
println!("{} {} {}", list.title.bold(), format!("({} tasks)", list.tasks.len()).dimmed(), "");
|
||||
|
||||
if list.tasks.is_empty() {
|
||||
println!(" No tasks");
|
||||
} else {
|
||||
for task in &list.tasks {
|
||||
let checkbox = if task.status == bevy_tasks_core::TaskStatus::Completed {
|
||||
"[✓]".green()
|
||||
} else {
|
||||
"[ ]".normal()
|
||||
};
|
||||
|
||||
let due_str = if let Some(due) = task.due_date {
|
||||
format!(" (due: {})", due.format("%Y-%m-%d")).yellow().to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let id_str = task.id.to_string();
|
||||
println!(" {} {}{} {}", checkbox, task.title, due_str, id_str.dimmed());
|
||||
}
|
||||
}
|
||||
output::header(&format!("{} ({})", list.title, format!("{} tasks", list.tasks.len()).dimmed()));
|
||||
print_tasks(&list.tasks);
|
||||
} else {
|
||||
// Show all lists
|
||||
for list in &lists {
|
||||
println!("{} {}", list.title.bold(), format!("({} tasks)", list.tasks.len()).dimmed());
|
||||
|
||||
if list.tasks.is_empty() {
|
||||
println!(" No tasks");
|
||||
} else {
|
||||
for task in &list.tasks {
|
||||
let checkbox = if task.status == bevy_tasks_core::TaskStatus::Completed {
|
||||
"[✓]".green()
|
||||
} else {
|
||||
"[ ]".normal()
|
||||
};
|
||||
|
||||
let due_str = if let Some(due) = task.due_date {
|
||||
format!(" (due: {})", due.format("%Y-%m-%d")).yellow().to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let id_str = task.id.to_string();
|
||||
println!(" {} {}{} {}", checkbox, task.title, due_str, id_str.dimmed());
|
||||
}
|
||||
}
|
||||
println!();
|
||||
output::header(&format!("{} ({})", list.title, format!("{} tasks", list.tasks.len()).dimmed()));
|
||||
print_tasks(&list.tasks);
|
||||
output::blank();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +78,7 @@ pub fn delete(name: String, workspace: Option<String>) -> Result<()> {
|
|||
io::stdin().read_line(&mut input)?;
|
||||
|
||||
if input.trim().to_lowercase() != "y" {
|
||||
println!("Cancelled");
|
||||
output::info("Cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ pub fn setup(workspace_name: Option<String>) -> Result<()> {
|
|||
};
|
||||
|
||||
// Prompt for WebDAV URL
|
||||
println!("WebDAV sync setup for workspace \"{}\"", name.green());
|
||||
println!();
|
||||
output::header(&format!("WebDAV sync setup for workspace \"{}\"", name.green()));
|
||||
output::blank();
|
||||
|
||||
let url = prompt("WebDAV URL: ")?;
|
||||
if url.is_empty() {
|
||||
|
|
@ -35,8 +35,8 @@ pub fn setup(workspace_name: Option<String>) -> Result<()> {
|
|||
.context("Failed to read password")?;
|
||||
|
||||
// Test connection
|
||||
println!();
|
||||
println!("Testing connection...");
|
||||
output::blank();
|
||||
output::info("Testing connection...");
|
||||
|
||||
let rt = tokio::runtime::Runtime::new().context("Failed to create async runtime")?;
|
||||
let client = WebDavClient::new(&url, &username, &password);
|
||||
|
|
@ -102,7 +102,7 @@ pub fn execute(mode: SyncMode, workspace_name: Option<String>) -> Result<()> {
|
|||
SyncMode::Push => "Pushing",
|
||||
SyncMode::Pull => "Pulling",
|
||||
};
|
||||
println!("{} workspace \"{}\"...", mode_str, name.green());
|
||||
output::info(&format!("{} workspace \"{}\"...", mode_str, name.green()));
|
||||
|
||||
let rt = tokio::runtime::Runtime::new().context("Failed to create async runtime")?;
|
||||
let result = rt.block_on(sync_workspace(
|
||||
|
|
@ -153,7 +153,7 @@ pub fn status(workspace_name: Option<String>, all: bool) -> Result<()> {
|
|||
if ws.webdav_url.is_some() {
|
||||
found_any = true;
|
||||
print_workspace_status(&name, &ws.path, ws.webdav_url.as_deref())?;
|
||||
println!();
|
||||
output::blank();
|
||||
}
|
||||
}
|
||||
if !found_any {
|
||||
|
|
@ -178,27 +178,27 @@ pub fn status(workspace_name: Option<String>, all: bool) -> Result<()> {
|
|||
}
|
||||
|
||||
fn print_workspace_status(name: &str, path: &std::path::Path, webdav_url: Option<&str>) -> Result<()> {
|
||||
println!("Workspace: {}", name.green());
|
||||
output::header(&format!("Workspace: {}", name.green()));
|
||||
|
||||
if let Some(url) = webdav_url {
|
||||
println!(" WebDAV URL: {}", url);
|
||||
output::detail("WebDAV URL", url);
|
||||
} else {
|
||||
println!(" WebDAV: {}", "not configured".dimmed());
|
||||
output::detail("WebDAV", &"not configured".dimmed().to_string());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let info = get_sync_status(path)?;
|
||||
|
||||
if let Some(last) = info.last_sync {
|
||||
println!(" Last sync: {}", last.format("%Y-%m-%d %H:%M:%S UTC"));
|
||||
output::detail("Last sync", &last.format("%Y-%m-%d %H:%M:%S UTC").to_string());
|
||||
} else {
|
||||
println!(" Last sync: {}", "never".dimmed());
|
||||
output::detail("Last sync", &"never".dimmed().to_string());
|
||||
}
|
||||
|
||||
println!(" Tracked files: {}", info.tracked_files);
|
||||
println!(" Pending changes: {}", info.pending_changes);
|
||||
output::detail("Tracked files", &info.tracked_files.to_string());
|
||||
output::detail("Pending changes", &info.pending_changes.to_string());
|
||||
if info.queued_operations > 0 {
|
||||
println!(" Queued operations: {}", format!("{}", info.queued_operations).yellow());
|
||||
output::detail("Queued operations", &format!("{}", info.queued_operations).yellow().to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub fn delete(task_id_str: String, workspace: Option<String>) -> Result<()> {
|
|||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
if input.trim().to_lowercase() != "y" {
|
||||
println!("Cancelled");
|
||||
output::info("Cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ pub fn add(name: String, path: String) -> Result<()> {
|
|||
// Save config
|
||||
save_config(&config)?;
|
||||
|
||||
output::success(&format!("Added workspace \"{}\" at {:?}", name, path_buf));
|
||||
output::success(&format!("Added workspace \"{}\" at {}", name, path_buf.display()));
|
||||
output::success("Created default list \"My Tasks\"");
|
||||
|
||||
Ok(())
|
||||
|
|
@ -48,7 +48,7 @@ pub fn list() -> Result<()> {
|
|||
let config = load_config()?;
|
||||
|
||||
if config.workspaces.is_empty() {
|
||||
println!("No workspaces configured. Use 'bevy-tasks init' to create one.");
|
||||
output::info("No workspaces configured. Use 'bevy-tasks init' to create one.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ pub fn list() -> Result<()> {
|
|||
} else {
|
||||
"".normal()
|
||||
};
|
||||
println!(" {}: {:?}{}", name, workspace_config.path, marker);
|
||||
output::item(&format!("{}: {}{}", name, workspace_config.path.display(), marker));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -103,7 +103,7 @@ pub fn remove(name: String) -> Result<()> {
|
|||
io::stdin().read_line(&mut input)?;
|
||||
|
||||
if input.trim().to_lowercase() != "y" {
|
||||
println!("Cancelled");
|
||||
output::info("Cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ pub fn retarget(name: String, path: String) -> Result<()> {
|
|||
config.add_workspace(name.clone(), WorkspaceConfig::new(path_buf.clone()));
|
||||
save_config(&config)?;
|
||||
|
||||
output::success(&format!("Workspace \"{}\" now points to {:?}", name, path_buf));
|
||||
output::success(&format!("Workspace \"{}\" now points to {}", name, path_buf.display()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ pub fn migrate(name: String, new_path: String) -> Result<()> {
|
|||
.path.clone();
|
||||
|
||||
// Confirm
|
||||
output::warning(&format!("This will move all files from {:?} to {:?}", old_path, new_path_buf));
|
||||
output::warning(&format!("This will move all files from {} to {}", old_path.display(), new_path_buf.display()));
|
||||
print!("Continue? (y/n): ");
|
||||
use std::io::{self, Write};
|
||||
io::stdout().flush()?;
|
||||
|
|
@ -164,7 +164,7 @@ pub fn migrate(name: String, new_path: String) -> Result<()> {
|
|||
io::stdin().read_line(&mut input)?;
|
||||
|
||||
if input.trim().to_lowercase() != "y" {
|
||||
println!("Cancelled");
|
||||
output::info("Cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ pub fn migrate(name: String, new_path: String) -> Result<()> {
|
|||
std::fs::create_dir_all(&new_path_buf)?;
|
||||
|
||||
// Move files
|
||||
println!("Moving files...");
|
||||
output::info("Moving files...");
|
||||
let entries = std::fs::read_dir(&old_path)?;
|
||||
let mut count = 0;
|
||||
|
||||
|
|
@ -185,10 +185,10 @@ pub fn migrate(name: String, new_path: String) -> Result<()> {
|
|||
let mut options = fs_extra::dir::CopyOptions::new();
|
||||
options.copy_inside = true;
|
||||
fs_extra::dir::move_dir(entry.path(), &new_path_buf, &options)?;
|
||||
println!(" Moved {:?}/", file_name);
|
||||
output::item(&format!("Moved {}/", file_name.to_string_lossy()));
|
||||
} else {
|
||||
std::fs::rename(entry.path(), dest)?;
|
||||
println!(" Moved {:?}", file_name);
|
||||
output::item(&format!("Moved {}", file_name.to_string_lossy()));
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
|
@ -202,8 +202,8 @@ pub fn migrate(name: String, new_path: String) -> Result<()> {
|
|||
config.add_workspace(name.clone(), WorkspaceConfig::new(new_path_buf.clone()));
|
||||
save_config(&config)?;
|
||||
|
||||
output::success(&format!("Migrated {} items to {:?}", count, new_path_buf));
|
||||
output::success(&format!("Workspace \"{}\" now points to {:?}", name, new_path_buf));
|
||||
output::success(&format!("Migrated {} items to {}", count, new_path_buf.display()));
|
||||
output::success(&format!("Workspace \"{}\" now points to {}", name, new_path_buf.display()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,3 +15,19 @@ pub fn warning(message: &str) {
|
|||
pub fn info(message: &str) {
|
||||
println!("{} {}", "ℹ".blue(), message);
|
||||
}
|
||||
|
||||
pub fn header(message: &str) {
|
||||
println!("{}", message.bold());
|
||||
}
|
||||
|
||||
pub fn detail(label: &str, value: &str) {
|
||||
println!(" {}: {}", label, value);
|
||||
}
|
||||
|
||||
pub fn item(message: &str) {
|
||||
println!(" {}", message);
|
||||
}
|
||||
|
||||
pub fn blank() {
|
||||
println!();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue