Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ serde_json = "1.0.113"
textwrap = { version = "0.15.2", features = ["terminal_size"] }
similar = { version = "2.4.0", features = ["inline"] }
console = "0.15.8"
crossterm = "0.27"
toml = "0.5.11"
log = "0.4.20"
indicatif = "0.16.2"
Expand Down
93 changes: 69 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use anyhow::{bail, Context, Result};
use clap::ArgEnum;
use console::{style, Term};
use indicatif::{MultiProgress, ProgressBar};
use console::Term;
use linter::Linter;
use log::debug;
use path::AbsPath;
Expand All @@ -13,6 +12,7 @@ use std::convert::TryFrom;
use std::fs::OpenOptions;
use std::sync::{Arc, Mutex};
use std::thread;
use terminal::TerminalManager;
use version_control::VersionControl;

pub mod git;
Expand All @@ -26,6 +26,7 @@ pub mod persistent_data;
pub mod rage;
pub mod render;
pub mod sapling;
pub mod terminal;
pub mod version_control;

#[cfg(test)]
Expand Down Expand Up @@ -216,25 +217,30 @@ pub fn do_lint(
log_utils::log_files("Linting files: ", &files);

let mut thread_handles = Vec::new();
let spinners = Arc::new(MultiProgress::new());

// Too lazy to learn rust's fancy concurrent programming stuff, just spawn a thread per linter and join them.
let all_lints = Arc::new(Mutex::new(HashMap::new()));

// Create terminal manager for progress display
let terminal_manager = if enable_spinners {
let mut tm = TerminalManager::new();
tm.enter_progress_mode()?;

// Add all linters to progress display
for linter in &linters {
tm.add_linter(linter.code.clone(), "running...".to_string());
}

Some(Arc::new(Mutex::new(tm)))
} else {
None
};

for linter in linters {
let all_lints = Arc::clone(&all_lints);
let files = Arc::clone(&files);
let spinners = Arc::clone(&spinners);
let linter_code = linter.code.clone();
let tm_clone = terminal_manager.clone();

let handle = thread::spawn(move || -> Result<()> {
let mut spinner = None;
if enable_spinners {
let _spinner = spinners.add(ProgressBar::new_spinner());
_spinner.set_message(format!("{} running...", linter.code));
_spinner.enable_steady_tick(100);
spinner = Some(_spinner);
}

let lints = linter.run(&files);

// If we're applying patches later, don't consider lints that would
Expand All @@ -250,24 +256,63 @@ pub fn do_lint(
let is_success = lints.is_empty();

group_lints_by_file(&mut all_lints, lints);

let spinner_message = if is_success {
format!("{} {}", linter.code, style("success!").green())
} else {
format!("{} {}", linter.code, style("failure").red())
};

if enable_spinners {
spinner.unwrap().finish_with_message(spinner_message);
drop(all_lints); // Release lock before updating progress

// Update progress display (non-blocking)
if let Some(tm) = tm_clone {
let message = if is_success {
"success!".to_string()
} else {
"failure".to_string()
};

// Quick non-blocking update
if let Ok(tm_guard) = tm.try_lock() {
tm_guard.update_linter(&linter_code, message, true, is_success);
}
}
Ok(())
});
thread_handles.push(handle);
}

spinners.join()?;
// Wait for all linters to complete with periodic refresh
let tm_for_refresh = terminal_manager.clone();
let completed_handles = Arc::new(Mutex::new(0));
let total_handles = thread_handles.len();

// Spawn a monitoring thread to refresh display
let completed_ref = completed_handles.clone();
let monitor_handle = if let Some(tm) = tm_for_refresh {
Some(thread::spawn(move || {
while *completed_ref.lock().unwrap() < total_handles {
if let Ok(tm_guard) = tm.try_lock() {
let _ = tm_guard.refresh_display();
}
thread::sleep(std::time::Duration::from_millis(100));
}
}))
} else {
None
};

// Wait for all linter threads
for handle in thread_handles {
handle.join().unwrap()?;
*completed_handles.lock().unwrap() += 1;
}

// Wait for monitor thread to finish
if let Some(handle) = monitor_handle {
handle.join().unwrap();
}

// Exit progress mode and return to normal terminal
if let Some(tm) = terminal_manager {
let mut tm_guard = tm.lock().unwrap();
// Brief pause to show final state
std::thread::sleep(std::time::Duration::from_millis(500));
tm_guard.exit_progress_mode()?;
}

// Unwrap is fine because all other owners hsould have been joined.
Expand Down
1 change: 0 additions & 1 deletion src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ pub fn render_lint_messages(
let current_dir = std::env::current_dir()?;
for path in paths {
let lint_messages = lint_messages.get(path).unwrap();

stdout.write_all(b"\n\n")?;

match path {
Expand Down
Loading
Loading