From 0b31b964d91ca715747b39a71b7e069e0f3e7164 Mon Sep 17 00:00:00 2001 From: kvvarun-mecha Date: Sun, 16 Mar 2025 16:06:18 +0530 Subject: [PATCH 1/5] bug: dynamic alloc of layout constraints in task details screen Changes i've made is for accomadating loong location names, ive changed the ... to the long name, it widens the task rectangle if its longer than the default 50% and goes to the next line if its longer than we can accomadate in a single line. This fixes issue #523 i have attached screenshots of the same in the PR, before and after changes --- tokio-console/src/view/task.rs | 96 ++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/tokio-console/src/view/task.rs b/tokio-console/src/view/task.rs index accb3fb07..1cfe52f5c 100644 --- a/tokio-console/src/view/task.rs +++ b/tokio-console/src/view/task.rs @@ -127,7 +127,7 @@ impl TaskView { ) }; - let stats_area = Layout::default() + let stats_area_check = Layout::default() .direction(layout::Direction::Horizontal) .constraints( [ @@ -138,6 +138,51 @@ impl TaskView { ) .split(stats_area); + let mut location_lines_vector: Vec = vec![]; + let title = "Location: "; + let location_max_width = stats_area_check[0].width as usize - 2 - title.len(); // NOTE: -2 for the border + let stats_area = if task.location().len() > location_max_width { + let max_width_stats_area = area.width - 45; + if max_width_stats_area < task.location().len() as u16 { + location_lines_vector = task + .location() + .to_string() + .chars() + .collect::>() + .chunks(max_width_stats_area as usize) + .map(|chunk| chunk.iter().collect()) + .collect(); + + let area_needed_to_render_location = task.location().len() as u16; + Layout::default() + .direction(layout::Direction::Horizontal) + .constraints( + [ + layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" + layout::Constraint::Min(32), + ] + .as_ref(), + ) + .split(stats_area) + } else { + let area_needed_to_render_location = task.location().len() as u16; + location_lines_vector.push(task.location().to_string()); + Layout::default() + .direction(layout::Direction::Horizontal) + .constraints( + [ + layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" + layout::Constraint::Min(32), + ] + .as_ref(), + ) + .split(stats_area) + } + } else { + location_lines_vector.push(task.location().to_string()); + stats_area_check + }; + // Just preallocate capacity for ID, name, target, total, busy, and idle. let mut overview = Vec::with_capacity(8); overview.push(Line::from(vec![ @@ -152,17 +197,13 @@ impl TaskView { overview.push(Line::from(vec![bold("Target: "), Span::raw(task.target())])); - let title = "Location: "; - let location_max_width = stats_area[0].width as usize - 2 - title.len(); // NOTE: -2 for the border - let location = if task.location().len() > location_max_width { - let ellipsis = styles.if_utf8("\u{2026}", "..."); - let start = task.location().len() - location_max_width + ellipsis.chars().count(); - format!("{}{}", ellipsis, &task.location()[start..]) - } else { - task.location().to_string() - }; - - overview.push(Line::from(vec![bold(title), Span::raw(location)])); + let first_line = location_lines_vector[0].clone(); + location_lines_vector.remove(0); + let location_vector = vec![bold(title), Span::raw(first_line)]; + overview.push(Line::from(location_vector)); + for line in location_lines_vector { + overview.push(Line::from(Span::raw(format!(" {}", line)))); + } let total = task.total(now); @@ -185,28 +226,37 @@ impl TaskView { let mut waker_stats = vec![Line::from(vec![ bold("Current wakers: "), - Span::from(format!("{} (", task.waker_count())), - bold("clones: "), - Span::from(format!("{}, ", task.waker_clones())), - bold("drops: "), - Span::from(format!("{})", task.waker_drops())), + Span::from(format!("{} ", task.waker_count())), ])]; + let waker_stats_clones = vec![ + bold(" Clones: "), + Span::from(format!("{}, ", task.waker_clones())), + ]; + + let waker_stats_drops = vec![ + bold(" Drops: "), + Span::from(format!("{}", task.waker_drops())), + ]; - let mut wakeups = vec![ + let wakeups = vec![ bold("Woken: "), Span::from(format!("{} times", task.wakes())), ]; + let mut last_woken_line = vec![]; + // If the task has been woken, add the time since wake to its stats as well. if let Some(since) = task.since_wake(now) { - wakeups.reserve(3); - wakeups.push(Span::raw(", ")); - wakeups.push(bold("last woken: ")); - wakeups.push(styles.time_units(since, view::DUR_LIST_PRECISION, None)); - wakeups.push(Span::raw(" ago")); + last_woken_line.reserve(3); + last_woken_line.push(bold("Last woken: ")); + last_woken_line.push(styles.time_units(since, view::DUR_LIST_PRECISION, None)); + last_woken_line.push(Span::raw(" ago")); } + waker_stats.push(Line::from(waker_stats_clones)); + waker_stats.push(Line::from(waker_stats_drops)); waker_stats.push(Line::from(wakeups)); + waker_stats.push(Line::from(last_woken_line)); if task.self_wakes() > 0 { waker_stats.push(Line::from(vec![ From 0f79e653d4e842ce057a5388a42bdaa105ade94f Mon Sep 17 00:00:00 2001 From: kvvarun-mecha Date: Fri, 21 Mar 2025 20:08:38 +0530 Subject: [PATCH 2/5] bug: idle line visible after dynamic alloc of layout constraints in task details screen I've made the logic to look whether Location is longer than a single viewable length, even before setting constraints both vertically and horizontally. This fixes issue #523 --- tokio-console/src/view/task.rs | 236 ++++++++++++++++++++------------- 1 file changed, 143 insertions(+), 93 deletions(-) diff --git a/tokio-console/src/view/task.rs b/tokio-console/src/view/task.rs index 1cfe52f5c..e2311e221 100644 --- a/tokio-console/src/view/task.rs +++ b/tokio-console/src/view/task.rs @@ -34,7 +34,6 @@ impl TaskView { pub(crate) fn update_input(&mut self, _event: input::Event) { // TODO :D } - pub(crate) fn render( &mut self, styles: &view::Styles, @@ -68,65 +67,6 @@ impl TaskView { }) .collect(); - let ( - controls_area, - stats_area, - poll_dur_area, - scheduled_dur_area, - fields_area, - warnings_area, - ) = if warnings.is_empty() { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // task stats - layout::Constraint::Length(10), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) - } else { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // warnings (add 2 for top and bottom borders) - layout::Constraint::Length(warnings.len() as u16 + 2), - // task stats - layout::Constraint::Length(10), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - - ( - chunks[0], - chunks[2], - chunks[3], - chunks[4], - chunks[5], - Some(chunks[1]), - ) - }; - let stats_area_check = Layout::default() .direction(layout::Direction::Horizontal) .constraints( @@ -136,51 +76,161 @@ impl TaskView { ] .as_ref(), ) - .split(stats_area); - - let mut location_lines_vector: Vec = vec![]; - let title = "Location: "; - let location_max_width = stats_area_check[0].width as usize - 2 - title.len(); // NOTE: -2 for the border - let stats_area = if task.location().len() > location_max_width { - let max_width_stats_area = area.width - 45; - if max_width_stats_area < task.location().len() as u16 { - location_lines_vector = task - .location() - .to_string() - .chars() - .collect::>() - .chunks(max_width_stats_area as usize) - .map(|chunk| chunk.iter().collect()) - .collect(); - - let area_needed_to_render_location = task.location().len() as u16; - Layout::default() - .direction(layout::Direction::Horizontal) + .split(area); + + let location_heading = "Location: "; + let location_max_width = stats_area_check[0].width as usize - 2 - location_heading.len(); // NOTE: -2 for the border + let max_width_stats_area = area.width - 45; + let mut location_lines_vector: Vec = task + .location() + .to_string() + .chars() + .collect::>() + .chunks(max_width_stats_area as usize) + .map(|chunk| chunk.iter().collect()) + .collect(); + let no_of_lines_extra_required_to_accomadate_location = location_lines_vector.len() - 1; + let ( + controls_area, + stats_area, + poll_dur_area, + scheduled_dur_area, + fields_area, + warnings_area, + ) = if task.location().len() > location_max_width { + if warnings.is_empty() { + let chunks = Layout::default() + .direction(layout::Direction::Vertical) + .constraints( + [ + // controls + layout::Constraint::Length(controls.height()), + // task stats + layout::Constraint::Length( + 10 + no_of_lines_extra_required_to_accomadate_location as u16, + ), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), + ] + .as_ref(), + ) + .split(area); + (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) + } else { + let chunks = Layout::default() + .direction(layout::Direction::Vertical) + .constraints( + [ + // controls + layout::Constraint::Length(controls.height()), + // warnings (add 2 for top and bottom borders) + layout::Constraint::Length(warnings.len() as u16 + 2), + // task stats + layout::Constraint::Length( + 10 + no_of_lines_extra_required_to_accomadate_location as u16, + ), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), + ] + .as_ref(), + ) + .split(area); + + ( + chunks[0], + chunks[2], + chunks[3], + chunks[4], + chunks[5], + Some(chunks[1]), + ) + } + } else { + if warnings.is_empty() { + let chunks = Layout::default() + .direction(layout::Direction::Vertical) .constraints( [ - layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" - layout::Constraint::Min(32), + // controls + layout::Constraint::Length(controls.height()), + // task stats + layout::Constraint::Length(10), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), ] .as_ref(), ) - .split(stats_area) + .split(area); + (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) } else { - let area_needed_to_render_location = task.location().len() as u16; - location_lines_vector.push(task.location().to_string()); - Layout::default() - .direction(layout::Direction::Horizontal) + let chunks = Layout::default() + .direction(layout::Direction::Vertical) .constraints( [ - layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" - layout::Constraint::Min(32), + // controls + layout::Constraint::Length(controls.height()), + // warnings (add 2 for top and bottom borders) + layout::Constraint::Length(warnings.len() as u16 + 2), + // task stats + layout::Constraint::Length(10), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), ] .as_ref(), ) - .split(stats_area) + .split(area); + + ( + chunks[0], + chunks[2], + chunks[3], + chunks[4], + chunks[5], + Some(chunks[1]), + ) } + }; + + let stats_area = if location_lines_vector.len() != 1 { + let area_needed_to_render_location = task.location().len() as u16; + Layout::default() + .direction(layout::Direction::Horizontal) + .constraints( + [ + layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" + layout::Constraint::Min(32), + ] + .as_ref(), + ) + .split(stats_area) } else { - location_lines_vector.push(task.location().to_string()); - stats_area_check + Layout::default() + .direction(layout::Direction::Horizontal) + .constraints( + [ + layout::Constraint::Percentage(50), + layout::Constraint::Percentage(50), + ] + .as_ref(), + ) + .split(stats_area) + // stats_area_check }; // Just preallocate capacity for ID, name, target, total, busy, and idle. @@ -199,7 +249,7 @@ impl TaskView { let first_line = location_lines_vector[0].clone(); location_lines_vector.remove(0); - let location_vector = vec![bold(title), Span::raw(first_line)]; + let location_vector = vec![bold(location_heading), Span::raw(first_line)]; overview.push(Line::from(location_vector)); for line in location_lines_vector { overview.push(Line::from(Span::raw(format!(" {}", line)))); From 2e5a512d6ffb035bebbc4c136ca3b2e31e417c6a Mon Sep 17 00:00:00 2001 From: kvvarun-mecha Date: Mon, 24 Mar 2025 18:06:54 +0530 Subject: [PATCH 3/5] bug: dynamic alloc of layout constraints, requested changes changed please refer to earlier commits to see what changes have been made --- tokio-console/src/view/task.rs | 209 +++++++++++---------------------- 1 file changed, 66 insertions(+), 143 deletions(-) diff --git a/tokio-console/src/view/task.rs b/tokio-console/src/view/task.rs index e2311e221..53b023352 100644 --- a/tokio-console/src/view/task.rs +++ b/tokio-console/src/view/task.rs @@ -34,6 +34,7 @@ impl TaskView { pub(crate) fn update_input(&mut self, _event: input::Event) { // TODO :D } + pub(crate) fn render( &mut self, styles: &view::Styles, @@ -67,21 +68,9 @@ impl TaskView { }) .collect(); - let stats_area_check = Layout::default() - .direction(layout::Direction::Horizontal) - .constraints( - [ - layout::Constraint::Percentage(50), - layout::Constraint::Percentage(50), - ] - .as_ref(), - ) - .split(area); - let location_heading = "Location: "; - let location_max_width = stats_area_check[0].width as usize - 2 - location_heading.len(); // NOTE: -2 for the border - let max_width_stats_area = area.width - 45; - let mut location_lines_vector: Vec = task + let max_width_stats_area = area.width - 45; //NOTE: 45 is min width needed, this is a calculated number according to the string: 'Last woken: 75.831727ms ago' but with some more extra pixels. + let location_lines_vector: Vec = task .location() .to_string() .chars() @@ -89,7 +78,8 @@ impl TaskView { .chunks(max_width_stats_area as usize) .map(|chunk| chunk.iter().collect()) .collect(); - let no_of_lines_extra_required_to_accomadate_location = location_lines_vector.len() - 1; + let task_stats_height = 9 + location_lines_vector.len() as u16; + // Id, Name, Target, Location (multiple), total, busy, scheduled, and idle times + top/bottom borders let ( controls_area, stats_area, @@ -97,141 +87,75 @@ impl TaskView { scheduled_dur_area, fields_area, warnings_area, - ) = if task.location().len() > location_max_width { - if warnings.is_empty() { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // task stats - layout::Constraint::Length( - 10 + no_of_lines_extra_required_to_accomadate_location as u16, - ), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) - } else { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // warnings (add 2 for top and bottom borders) - layout::Constraint::Length(warnings.len() as u16 + 2), - // task stats - layout::Constraint::Length( - 10 + no_of_lines_extra_required_to_accomadate_location as u16, - ), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - - ( - chunks[0], - chunks[2], - chunks[3], - chunks[4], - chunks[5], - Some(chunks[1]), - ) - } - } else { - if warnings.is_empty() { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // task stats - layout::Constraint::Length(10), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) - } else { - let chunks = Layout::default() - .direction(layout::Direction::Vertical) - .constraints( - [ - // controls - layout::Constraint::Length(controls.height()), - // warnings (add 2 for top and bottom borders) - layout::Constraint::Length(warnings.len() as u16 + 2), - // task stats - layout::Constraint::Length(10), - // poll duration - layout::Constraint::Length(9), - // scheduled duration - layout::Constraint::Length(9), - // fields - layout::Constraint::Percentage(60), - ] - .as_ref(), - ) - .split(area); - - ( - chunks[0], - chunks[2], - chunks[3], - chunks[4], - chunks[5], - Some(chunks[1]), - ) - } - }; - - let stats_area = if location_lines_vector.len() != 1 { - let area_needed_to_render_location = task.location().len() as u16; - Layout::default() - .direction(layout::Direction::Horizontal) + ) = if warnings.is_empty() { + let chunks = Layout::default() + .direction(layout::Direction::Vertical) .constraints( [ - layout::Constraint::Min(area_needed_to_render_location + 15), //Note: 15 is the length of "| Location: |" - layout::Constraint::Min(32), + // controls + layout::Constraint::Length(controls.height()), + // task stats + layout::Constraint::Length(task_stats_height), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), ] .as_ref(), ) - .split(stats_area) + .split(area); + (chunks[0], chunks[1], chunks[2], chunks[3], chunks[4], None) } else { - Layout::default() - .direction(layout::Direction::Horizontal) + let chunks = Layout::default() + .direction(layout::Direction::Vertical) .constraints( [ - layout::Constraint::Percentage(50), - layout::Constraint::Percentage(50), + // controls + layout::Constraint::Length(controls.height()), + // warnings (add 2 for top and bottom borders) + layout::Constraint::Length(warnings.len() as u16 + 2), + // task stats + layout::Constraint::Length(task_stats_height), + // poll duration + layout::Constraint::Length(9), + // scheduled duration + layout::Constraint::Length(9), + // fields + layout::Constraint::Percentage(60), ] .as_ref(), ) - .split(stats_area) - // stats_area_check + .split(area); + + ( + chunks[0], + chunks[2], + chunks[3], + chunks[4], + chunks[5], + Some(chunks[1]), + ) + }; + + let stats_constraints = if location_lines_vector.len() > 1 { + let area_needed_to_render_location = task.location().len() as u16; + [ + // 15 is the length of "| Location: |" + layout::Constraint::Min(area_needed_to_render_location + 15), + layout::Constraint::Min(32), + ] + } else { + [ + layout::Constraint::Percentage(50), + layout::Constraint::Percentage(50), + ] }; + let stats_area = Layout::default() + .direction(layout::Direction::Horizontal) + .constraints(stats_constraints.as_ref()) + .split(stats_area); // Just preallocate capacity for ID, name, target, total, busy, and idle. let mut overview = Vec::with_capacity(8); @@ -247,12 +171,11 @@ impl TaskView { overview.push(Line::from(vec![bold("Target: "), Span::raw(task.target())])); - let first_line = location_lines_vector[0].clone(); - location_lines_vector.remove(0); - let location_vector = vec![bold(location_heading), Span::raw(first_line)]; + let location_vector = vec![bold(location_heading), Span::raw(&location_lines_vector[0])]; overview.push(Line::from(location_vector)); - for line in location_lines_vector { - overview.push(Line::from(Span::raw(format!(" {}", line)))); + for line in &location_lines_vector[1..] { + overview.push(Line::from(Span::raw(format!(" {}", line)))); + //10 spaces to be precise due to the Length of "Location: " } let total = task.total(now); From 93319d5caa985174e0b4514621fcaf88896a2633 Mon Sep 17 00:00:00 2001 From: K V Varun Krishnan <116856685+vrn21@users.noreply.github.com> Date: Tue, 25 Mar 2025 19:29:24 +0530 Subject: [PATCH 4/5] bug fix: dynamic alloc of layout constraints in task details screen, long var names changed to shorter names Co-authored-by: Hayden Stainsby --- tokio-console/src/view/task.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-console/src/view/task.rs b/tokio-console/src/view/task.rs index 53b023352..e3248e04a 100644 --- a/tokio-console/src/view/task.rs +++ b/tokio-console/src/view/task.rs @@ -140,10 +140,10 @@ impl TaskView { }; let stats_constraints = if location_lines_vector.len() > 1 { - let area_needed_to_render_location = task.location().len() as u16; + let location_len = task.location().len() as u16; [ // 15 is the length of "| Location: |" - layout::Constraint::Min(area_needed_to_render_location + 15), + layout::Constraint::Min(location_len + 15), layout::Constraint::Min(32), ] } else { From 3ed638748a1b847c909ae23dcf8cb8e422d20017 Mon Sep 17 00:00:00 2001 From: kvvarun-mecha Date: Fri, 28 Mar 2025 00:32:28 +0530 Subject: [PATCH 5/5] buf: refactored if block in task constraints --- tokio-console/src/view/task.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/tokio-console/src/view/task.rs b/tokio-console/src/view/task.rs index e3248e04a..9e7969a05 100644 --- a/tokio-console/src/view/task.rs +++ b/tokio-console/src/view/task.rs @@ -139,19 +139,12 @@ impl TaskView { ) }; - let stats_constraints = if location_lines_vector.len() > 1 { - let location_len = task.location().len() as u16; - [ - // 15 is the length of "| Location: |" - layout::Constraint::Min(location_len + 15), - layout::Constraint::Min(32), - ] - } else { - [ - layout::Constraint::Percentage(50), - layout::Constraint::Percentage(50), - ] - }; + let stats_constraints = [ + // 15 is the length of "| Location: |" + layout::Constraint::Min(task.location().len() as u16 + 15), + layout::Constraint::Min(32), + ]; + let stats_area = Layout::default() .direction(layout::Direction::Horizontal) .constraints(stats_constraints.as_ref())