refactor(who): make --limit optional (unlimited default) and fix clippy sort lints

Change the `who` command's --limit flag from default=20 to optional,
so omitting it returns all results. This matches the behavior users
expect when they want a complete expert/workload/active/overlap listing
without an arbitrary cap.

Also applies clippy-recommended sort improvements:
- who/reviews: sort_by(|a,b| b.count.cmp(&a.count)) -> sort_by_key with Reverse
- drift: same pattern for frequency sorting

Adds Theme::color_icon() helper to DRY the stage-icon coloring pattern
used in sync output (was inline closure, now shared method).
This commit is contained in:
teernisse
2026-02-18 16:27:48 -05:00
parent 30ed02c694
commit ea6e45e43f
6 changed files with 25 additions and 15 deletions

View File

@@ -382,7 +382,7 @@ fn extract_drift_topics(description: &str, notes: &[NoteRow], drift_idx: usize)
} }
let mut sorted: Vec<(String, usize)> = freq.into_iter().collect(); let mut sorted: Vec<(String, usize)> = freq.into_iter().collect();
sorted.sort_by(|a, b| b.1.cmp(&a.1)); sorted.sort_by_key(|b| std::cmp::Reverse(b.1));
sorted sorted
.into_iter() .into_iter()

View File

@@ -143,6 +143,8 @@ pub fn run_who(config: &Config, args: &WhoArgs) -> Result<WhoRun> {
"none" "none"
}; };
let limit = args.limit.map_or(usize::MAX, usize::from);
match mode { match mode {
WhoMode::Expert { path } => { WhoMode::Expert { path } => {
// Compute as_of first so --since durations are relative to it. // Compute as_of first so --since durations are relative to it.
@@ -159,7 +161,6 @@ pub fn run_who(config: &Config, args: &WhoArgs) -> Result<WhoRun> {
} else { } else {
resolve_since_from(args.since.as_deref(), "24m", as_of_ms)? resolve_since_from(args.since.as_deref(), "24m", as_of_ms)?
}; };
let limit = usize::from(args.limit);
let result = expert::query_expert( let result = expert::query_expert(
&conn, &conn,
&path, &path,
@@ -191,7 +192,7 @@ pub fn run_who(config: &Config, args: &WhoArgs) -> Result<WhoRun> {
.as_deref() .as_deref()
.map(resolve_since_required) .map(resolve_since_required)
.transpose()?; .transpose()?;
let limit = usize::from(args.limit);
let result = workload::query_workload( let result = workload::query_workload(
&conn, &conn,
username, username,
@@ -231,7 +232,7 @@ pub fn run_who(config: &Config, args: &WhoArgs) -> Result<WhoRun> {
} }
WhoMode::Active => { WhoMode::Active => {
let since_ms = resolve_since(args.since.as_deref(), "7d")?; let since_ms = resolve_since(args.since.as_deref(), "7d")?;
let limit = usize::from(args.limit);
let result = let result =
active::query_active(&conn, project_id, since_ms, limit, args.include_closed)?; active::query_active(&conn, project_id, since_ms, limit, args.include_closed)?;
Ok(WhoRun { Ok(WhoRun {
@@ -249,7 +250,7 @@ pub fn run_who(config: &Config, args: &WhoArgs) -> Result<WhoRun> {
} }
WhoMode::Overlap { path } => { WhoMode::Overlap { path } => {
let since_ms = resolve_since(args.since.as_deref(), "30d")?; let since_ms = resolve_since(args.since.as_deref(), "30d")?;
let limit = usize::from(args.limit);
let result = overlap::query_overlap(&conn, &path, project_id, since_ms, limit)?; let result = overlap::query_overlap(&conn, &path, project_id, since_ms, limit)?;
Ok(WhoRun { Ok(WhoRun {
resolved_input: WhoResolvedInput { resolved_input: WhoResolvedInput {

View File

@@ -105,7 +105,7 @@ pub(super) fn query_reviews(
}) })
.collect(); .collect();
categories.sort_by(|a, b| b.count.cmp(&a.count)); categories.sort_by_key(|b| std::cmp::Reverse(b.count));
Ok(ReviewsResult { Ok(ReviewsResult {
username: username.to_string(), username: username.to_string(),

View File

@@ -18,7 +18,7 @@ pub struct WhoResolvedInput {
pub since_iso: Option<String>, pub since_iso: Option<String>,
/// "default" (mode default applied), "explicit" (user provided --since), "none" (no window) /// "default" (mode default applied), "explicit" (user provided --since), "none" (no window)
pub since_mode: String, pub since_mode: String,
pub limit: u16, pub limit: Option<u16>,
} }
/// Top-level result enum -- one variant per mode. /// Top-level result enum -- one variant per mode.

View File

@@ -286,7 +286,7 @@ fn test_is_file_path_discrimination() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -310,7 +310,7 @@ fn test_is_file_path_discrimination() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -334,7 +334,7 @@ fn test_is_file_path_discrimination() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -358,7 +358,7 @@ fn test_is_file_path_discrimination() {
reviews: true, reviews: true,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -382,7 +382,7 @@ fn test_is_file_path_discrimination() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -406,7 +406,7 @@ fn test_is_file_path_discrimination() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: false, detail: false,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -431,7 +431,7 @@ fn test_detail_rejected_outside_expert_mode() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: true, detail: true,
no_detail: false, no_detail: false,
fields: None, fields: None,
@@ -460,7 +460,7 @@ fn test_detail_allowed_in_expert_mode() {
reviews: false, reviews: false,
since: None, since: None,
project: None, project: None,
limit: 20, limit: None,
detail: true, detail: true,
no_detail: false, no_detail: false,
fields: None, fields: None,

View File

@@ -448,6 +448,15 @@ impl Theme {
Style::new() Style::new()
} }
} }
/// Apply semantic color to a stage-completion icon glyph.
pub fn color_icon(icon: &str, has_errors: bool) -> String {
if has_errors {
Self::warning().render(icon)
} else {
Self::success().render(icon)
}
}
} }
// ─── Shared Formatters ─────────────────────────────────────────────────────── // ─── Shared Formatters ───────────────────────────────────────────────────────