diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 231ecf348f407..e7647b452a440 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -89,15 +89,106 @@ pub fn fetch_grammars() -> Result<()> { let mut grammars = get_grammar_configs()?; grammars.retain(|grammar| !matches!(grammar.source, GrammarSource::Local { .. })); - run_parallel(grammars, fetch_grammar, "fetch") + print!("Fetching {} grammars", grammars.len()); + let results = run_parallel(grammars, fetch_grammar); + println!(" ... done"); + + let mut errors = Vec::new(); + let mut git_updated = Vec::new(); + let mut git_up_to_date = Vec::new(); + let mut non_git = Vec::new(); + + for res in results { + match res { + Ok(FetchSuccess { + grammar_id, + action: FetchAction::GitUpdated { revision }, + }) => git_updated.push(format!("{}->{}", grammar_id, revision)), + Ok(FetchSuccess { + grammar_id, + action: FetchAction::GitUpToDate, + }) => git_up_to_date.push(grammar_id), + Ok(FetchSuccess { + grammar_id, + action: FetchAction::NonGit, + }) => non_git.push(grammar_id), + Err(e) => errors.push(e), + } + } + + // People will easily find the grammar they want that way + git_updated.sort_unstable(); + git_up_to_date.sort_unstable(); + non_git.sort_unstable(); + + if !git_up_to_date.is_empty() { + println!("{:02} up to date git grammars", git_up_to_date.len()); + } + if !non_git.is_empty() { + println!("{:02} non git grammars", non_git.len()); + println!(" {:?}", non_git); + } + + if !git_updated.is_empty() { + println!("{:02} updated grammars", git_updated.len()); + println!(" {:?}", git_updated); + } + if !errors.is_empty() { + let len = errors.len(); + println!("{:02} grammars failed to fetch", len); + for (i, error) in errors.into_iter().enumerate() { + println!(" Failure {:02}/{:02}: {}", i, len, error); + } + } + + Ok(()) } pub fn build_grammars(target: Option) -> Result<()> { - run_parallel( - get_grammar_configs()?, - move |grammar| build_grammar(grammar, target.as_deref()), - "build", - ) + let grammars = get_grammar_configs()?; + print!("Building {} grammars", grammars.len()); + let results = run_parallel(grammars, move |grammar| { + build_grammar(grammar, target.as_deref()) + }); + println!(" ... done"); + + let mut errors = Vec::new(); + let mut built = Vec::new(); + let mut already_built = Vec::new(); + + for res in results { + match res { + Ok(BuildSuccess { + grammar_id, + action: BuildAction::Built, + }) => built.push(grammar_id), + Ok(BuildSuccess { + grammar_id, + action: BuildAction::AlreadyBuilt, + }) => already_built.push(grammar_id), + Err(e) => errors.push(e), + } + } + + built.sort_unstable(); + already_built.sort_unstable(); + + if !already_built.is_empty() { + println!("{:02} grammars already built", already_built.len()); + } + if !built.is_empty() { + println!("{:02} grammars built now", built.len()); + println!(" {:?}", built); + } + if !errors.is_empty() { + let len = errors.len(); + println!("{:02} grammars failed to build", len); + for (i, error) in errors.into_iter().enumerate() { + println!(" Failure {:02}/{:02}: {}", i, len, error); + } + } + + Ok(()) } // Returns the set of grammar configurations the user requests. @@ -126,9 +217,10 @@ fn get_grammar_configs() -> Result> { Ok(grammars) } -fn run_parallel(grammars: Vec, job: F, action: &'static str) -> Result<()> +fn run_parallel(grammars: Vec, job: F) -> Vec> where - F: Fn(GrammarConfiguration) -> Result<()> + std::marker::Send + 'static + Clone, + F: Fn(GrammarConfiguration) -> Result + Send + 'static + Clone, + Res: Send + 'static, { let pool = threadpool::Builder::new().build(); let (tx, rx) = channel(); @@ -146,14 +238,21 @@ where drop(tx); - // TODO: print all failures instead of the first one found. - rx.iter() - .find(|result| result.is_err()) - .map(|err| err.with_context(|| format!("Failed to {} some grammar(s)", action))) - .unwrap_or(Ok(())) + rx.iter().collect() } -fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> { +struct FetchSuccess { + grammar_id: String, + action: FetchAction, +} + +enum FetchAction { + GitUpdated { revision: String }, + GitUpToDate, + NonGit, +} + +fn fetch_grammar(grammar: GrammarConfiguration) -> Result { if let GrammarSource::Git { remote, revision, .. } = grammar.source @@ -189,16 +288,27 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> { )?; git(&grammar_dir, ["checkout", &revision])?; - println!( - "Grammar '{}' checked out at '{}'.", - grammar.grammar_id, revision - ); + Ok(FetchSuccess { + grammar_id: grammar.grammar_id, + action: FetchAction::GitUpdated { revision }, + }) + // println!( + // "Grammar '{}' checked out at '{}'.", + // grammar.grammar_id, revision + // ); } else { - println!("Grammar '{}' is already up to date.", grammar.grammar_id); + Ok(FetchSuccess { + grammar_id: grammar.grammar_id, + action: FetchAction::GitUpToDate, + }) + // println!("Grammar '{}' is already up to date.", grammar.grammar_id); } + } else { + Ok(FetchSuccess { + grammar_id: grammar.grammar_id, + action: FetchAction::NonGit, + }) } - - Ok(()) } // Sets the remote for a repository to the given URL, creating the remote if @@ -245,7 +355,17 @@ where } } -fn build_grammar(grammar: GrammarConfiguration, target: Option<&str>) -> Result<()> { +struct BuildSuccess { + grammar_id: String, + action: BuildAction, +} + +enum BuildAction { + Built, + AlreadyBuilt, +} + +fn build_grammar(grammar: GrammarConfiguration, target: Option<&str>) -> Result { let grammar_dir = if let GrammarSource::Local { path } = &grammar.source { PathBuf::from(&path) } else { @@ -285,7 +405,7 @@ fn build_tree_sitter_library( src_path: &Path, grammar: GrammarConfiguration, target: Option<&str>, -) -> Result<()> { +) -> Result { let header_path = src_path; let parser_path = src_path.join("parser.c"); let mut scanner_path = src_path.join("scanner.c"); @@ -308,12 +428,12 @@ fn build_tree_sitter_library( .context("Failed to compare source and binary timestamps")?; if !recompile { - println!("Grammar '{}' is already built.", grammar.grammar_id); - return Ok(()); + return Ok(BuildSuccess { + grammar_id: grammar.grammar_id, + action: BuildAction::AlreadyBuilt, + }); } - println!("Building grammar '{}'", grammar.grammar_id); - let mut config = cc::Build::new(); config .cpp(true) @@ -381,7 +501,10 @@ fn build_tree_sitter_library( )); } - Ok(()) + Ok(BuildSuccess { + grammar_id: grammar.grammar_id, + action: BuildAction::Built, + }) } fn needs_recompile(