From 92dcfc2592676d981296885675524858c5fcab3b Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Mon, 2 Jun 2025 20:15:33 -0700 Subject: [PATCH] Clean up CHKDSK log to prevent rendering issues CR escapes were causing text to render well outside the intended area. --- Cargo.lock | 1 + boot_diags/Cargo.toml | 1 + boot_diags/src/app.rs | 11 +++++--- boot_diags/src/diags.rs | 56 ++++++++++++++++++++++++++++++++++++----- config/config.json5 | 1 + 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d55a66f..e156095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,6 +196,7 @@ dependencies = [ "crossterm", "futures", "ratatui", + "regex", "serde", "tokio", "toml", diff --git a/boot_diags/Cargo.toml b/boot_diags/Cargo.toml index 719b395..8ee91f4 100644 --- a/boot_diags/Cargo.toml +++ b/boot_diags/Cargo.toml @@ -41,6 +41,7 @@ tracing = "0.1.41" tracing-error = "0.2.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] } check_elevation = "0.2.4" +regex = "1.11.1" [build-dependencies] anyhow = "1.0.86" diff --git a/boot_diags/src/app.rs b/boot_diags/src/app.rs index a526732..503b82b 100644 --- a/boot_diags/src/app.rs +++ b/boot_diags/src/app.rs @@ -728,19 +728,22 @@ fn get_chunks(r: Rect) -> Vec { fn build_footer_string(cur_mode: Mode) -> String { match cur_mode { - Mode::BootDiags | Mode::LogView => { + Mode::BootDiags => { String::from("(Enter) to select / (m) for menu / (s) to start over / (q) to quit") } Mode::BootScan | Mode::BootSetup | Mode::Home | Mode::ScanDisks => { String::from("(q) to quit") } - Mode::InstallDrivers | Mode::InjectDrivers | Mode::SetBootMode => { - String::from("(Enter) to select / (q) to quit") - } Mode::DiagMenu | Mode::SelectParts => { String::from("(Enter) to select / (s) to start over / (q) to quit") } Mode::Done => String::from("(Enter) to continue / (q) to quit"), + Mode::InstallDrivers | Mode::InjectDrivers | Mode::SetBootMode => { + String::from("(Enter) to select / (q) to quit") + } + Mode::LogView => { + String::from("(Enter | Esc) to close log / (up | down) to scroll / (q) to quit") + } Mode::SelectDisks => String::from( "(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit", ), diff --git a/boot_diags/src/diags.rs b/boot_diags/src/diags.rs index aba4e92..2429ac9 100644 --- a/boot_diags/src/diags.rs +++ b/boot_diags/src/diags.rs @@ -14,11 +14,38 @@ // along with Deja-Vu. If not, see . use core::{line::DVLine, tasks::TaskResult}; -use std::{fmt, thread::sleep, time::Duration}; +use std::{fmt, sync::OnceLock, thread::sleep, time::Duration}; use ratatui::style::Color; +use regex::Regex; use tracing::{info, warn}; +pub struct RegexList { + carriage_returns: OnceLock, + chkdsk_splits: OnceLock, +} + +impl RegexList { + fn carriage_returns(&self) -> &Regex { + self.carriage_returns + .get_or_init(|| Regex::new(r"^.*\r").unwrap()) + } + + fn chkdsk_splits(&self) -> &Regex { + self.chkdsk_splits.get_or_init(|| { + Regex::new( + r"(?m)^(WARNING|Stage |Windows |\d+.* total disk space|.*each allocation unit|Total duration)", + ) + .unwrap() + }) + } +} + +static REGEXES: RegexList = RegexList { + carriage_returns: OnceLock::new(), + chkdsk_splits: OnceLock::new(), +}; + #[derive(Clone, Copy, Debug)] pub enum Type { Bitlocker, @@ -53,7 +80,6 @@ pub struct Log { #[derive(Clone, Debug)] pub struct DiagGroup { - pub complete: bool, pub diag_type: Type, pub passed: bool, pub logs: Vec, @@ -63,7 +89,6 @@ pub struct DiagGroup { impl DiagGroup { pub fn new(diag_type: Type) -> Self { DiagGroup { - complete: false, diag_type, passed: true, logs: Vec::new(), @@ -124,7 +149,26 @@ pub fn parse_chkdsk(diag_group: &mut DiagGroup, task_result: TaskResult) { }); } TaskResult::Output(stdout, stderr, _) => { - if stdout.contains("Windows has scanned the file system and found no problems.") { + let re_carriage_returns = REGEXES.carriage_returns(); + let re_chkdsk_splits = REGEXES.chkdsk_splits(); + let output_text = if stderr.is_empty() { + stdout.clone() + } else { + format!("{stdout}\n\n-------\n\n{stderr}") + }; + let parsed_lines: Vec = output_text + .split("\r\n") + .filter_map(|line| { + let line = re_carriage_returns.replace_all(line, "").trim().to_string(); + if line.is_empty() { None } else { Some(line) } + }) + .collect(); + let parsed_output = re_chkdsk_splits + .replace_all(parsed_lines.join("\n").as_str(), "\n $1") + .to_string(); + + if parsed_output.contains("Windows has scanned the file system and found no problems.") + { diag_group.passed &= true; diag_group.result = String::from("OK"); diag_group.logs.push(Log { @@ -133,7 +177,7 @@ pub fn parse_chkdsk(diag_group: &mut DiagGroup, task_result: TaskResult) { line_parts: vec![String::from("CHKDSK: "), String::from("OK")], line_colors: vec![Color::Reset, Color::Green], }], - raw: format!("{stdout}\n\n-------\n\n{stderr}"), + raw: parsed_output, }); } else { diag_group.passed = false; @@ -144,7 +188,7 @@ pub fn parse_chkdsk(diag_group: &mut DiagGroup, task_result: TaskResult) { line_parts: vec![String::from("CHKDSK: "), String::from("Error")], line_colors: vec![Color::Reset, Color::Red], }], - raw: format!("{stdout}\n\n-------\n\n{stderr}"), + raw: parsed_output, }); } } diff --git a/config/config.json5 b/config/config.json5 index d54ebb2..4d64cda 100644 --- a/config/config.json5 +++ b/config/config.json5 @@ -133,6 +133,7 @@ }, "LogView": { "": "Process", + "": "Process", "": "KeyUp", "": "KeyDown", "": "Quit",