refactor(sync): overhaul progress display with stage spinners and summaries
Phase 2 of the UX overhaul. Replaces the old numbered-stage progress system (1/4, 2/4...) and manual indicatif ProgressBar/ProgressStyle setup with the new centralized progress helpers. Sync command changes (src/cli/commands/sync.rs): - Replace stage_spinner(n, total, msg) with stage_spinner_v2(icon, label, status) removing the rigid numbered-stage counter in favor of named stages - Replace manual ProgressBar::new + ProgressStyle::default_bar for docs and embed sub-progress with nested_progress(label, len, robot_mode) - Add finish_stage() calls that display a completion summary with elapsed time, e.g. "Issues 42 issues from 3 projects 1.2s" - Each stage (Issues, MRs, Docs, Embed) now reports what it did on completion rather than just clearing the spinner silently - Embed failure path uses Icons::warning() instead of inline Theme formatting, keeping error display consistent with success path - Remove indicatif direct dependency from sync.rs (now handled by progress module) Main entry point changes (src/main.rs): - Add GlyphMode detection: auto-detect Unicode/Nerd Font support or fall back to ASCII based on --icons flag, --color=never, NO_COLOR, or robot mode - Update all LoreRenderer::init() calls to pass GlyphMode alongside ColorMode for icon-aware rendering throughout the CLI - Overhaul handle_error() formatting: use Icons::error() glyph, bold error text, arrow prefixed action suggestions, and breathing room with blank lines for scannability - Migrate handle_embed() progress bar from manual ProgressBar + ProgressStyle to nested_progress() helper, matching sync command Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
teernisse
parent
96b288ccdd
commit
af8fc4af76
54
src/main.rs
54
src/main.rs
@@ -25,7 +25,7 @@ use lore::cli::commands::{
|
||||
run_list_issues, run_list_mrs, run_search, run_show_issue, run_show_mr, run_stats, run_sync,
|
||||
run_sync_status, run_timeline, run_who,
|
||||
};
|
||||
use lore::cli::render::{ColorMode, LoreRenderer, Theme};
|
||||
use lore::cli::render::{ColorMode, GlyphMode, Icons, LoreRenderer, Theme};
|
||||
use lore::cli::robot::{RobotMeta, strip_schemas};
|
||||
use lore::cli::{
|
||||
Cli, Commands, CountArgs, EmbedArgs, GenerateDocsArgs, IngestArgs, IssuesArgs, MrsArgs,
|
||||
@@ -145,24 +145,29 @@ async fn main() {
|
||||
}
|
||||
|
||||
// I1: Respect NO_COLOR convention (https://no-color.org/)
|
||||
let force_ascii = robot_mode
|
||||
|| cli.color == "never"
|
||||
|| std::env::var("NO_COLOR").is_ok_and(|v| !v.is_empty());
|
||||
let glyphs = GlyphMode::detect(cli.icons.as_deref(), force_ascii);
|
||||
|
||||
if std::env::var("NO_COLOR").is_ok_and(|v| !v.is_empty()) {
|
||||
LoreRenderer::init(ColorMode::Never);
|
||||
LoreRenderer::init(ColorMode::Never, glyphs);
|
||||
console::set_colors_enabled(false);
|
||||
} else {
|
||||
match cli.color.as_str() {
|
||||
"never" => {
|
||||
LoreRenderer::init(ColorMode::Never);
|
||||
LoreRenderer::init(ColorMode::Never, glyphs);
|
||||
console::set_colors_enabled(false);
|
||||
}
|
||||
"always" => {
|
||||
LoreRenderer::init(ColorMode::Always);
|
||||
LoreRenderer::init(ColorMode::Always, glyphs);
|
||||
console::set_colors_enabled(true);
|
||||
}
|
||||
"auto" => {
|
||||
LoreRenderer::init(ColorMode::Auto);
|
||||
LoreRenderer::init(ColorMode::Auto, glyphs);
|
||||
}
|
||||
other => {
|
||||
LoreRenderer::init(ColorMode::Auto);
|
||||
LoreRenderer::init(ColorMode::Auto, glyphs);
|
||||
eprintln!("Warning: unknown color mode '{}', using auto", other);
|
||||
}
|
||||
}
|
||||
@@ -409,21 +414,28 @@ fn handle_error(e: Box<dyn std::error::Error>, robot_mode: bool) -> ! {
|
||||
);
|
||||
std::process::exit(gi_error.exit_code());
|
||||
} else {
|
||||
eprintln!("{} {}", Theme::error().render("Error:"), gi_error);
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
" {} {}",
|
||||
Theme::error().render(Icons::error()),
|
||||
Theme::error().bold().render(&gi_error.to_string())
|
||||
);
|
||||
if let Some(suggestion) = gi_error.suggestion() {
|
||||
eprintln!("{} {}", Theme::warning().render("Hint:"), suggestion);
|
||||
eprintln!();
|
||||
eprintln!(" {suggestion}");
|
||||
}
|
||||
let actions = gi_error.actions();
|
||||
if !actions.is_empty() {
|
||||
eprintln!();
|
||||
for action in &actions {
|
||||
eprintln!(
|
||||
" {} {}",
|
||||
Theme::dim().render("$"),
|
||||
" {} {}",
|
||||
Theme::dim().render("\u{2192}"),
|
||||
Theme::bold().render(action)
|
||||
);
|
||||
}
|
||||
}
|
||||
eprintln!();
|
||||
std::process::exit(gi_error.exit_code());
|
||||
}
|
||||
}
|
||||
@@ -443,7 +455,13 @@ fn handle_error(e: Box<dyn std::error::Error>, robot_mode: bool) -> ! {
|
||||
})
|
||||
);
|
||||
} else {
|
||||
eprintln!("{} {}", Theme::error().render("Error:"), e);
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
" {} {}",
|
||||
Theme::error().render(Icons::error()),
|
||||
Theme::error().bold().render(&e.to_string())
|
||||
);
|
||||
eprintln!();
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
@@ -1966,7 +1984,6 @@ async fn handle_embed(
|
||||
args: EmbedArgs,
|
||||
robot_mode: bool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
@@ -1985,18 +2002,7 @@ async fn handle_embed(
|
||||
std::process::exit(130);
|
||||
});
|
||||
|
||||
let embed_bar = if robot_mode {
|
||||
ProgressBar::hidden()
|
||||
} else {
|
||||
let b = lore::cli::progress::multi().add(ProgressBar::new(0));
|
||||
b.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template(" {spinner:.blue} Generating embeddings [{bar:30.cyan/dim}] {pos}/{len}")
|
||||
.unwrap()
|
||||
.progress_chars("=> "),
|
||||
);
|
||||
b
|
||||
};
|
||||
let embed_bar = lore::cli::progress::nested_progress("Embedding", 0, robot_mode);
|
||||
let bar_clone = embed_bar.clone();
|
||||
let tick_started = Arc::new(AtomicBool::new(false));
|
||||
let tick_clone = Arc::clone(&tick_started);
|
||||
|
||||
Reference in New Issue
Block a user