From 3b6251ec3336e085d2ab68f4013114f3af76f4eb Mon Sep 17 00:00:00 2001 From: alex-xr555 Date: Thu, 24 Sep 2026 01:10:19 +0300 Subject: [PATCH] refactor: the style system has been changed and replaced functions (printc, colored) have been removed in src/utils/cli_styles.rs. Most files in src/cli have been heavily modified to migrate to the new system --- src/cli/add.rs | 19 +++++++------- src/cli/build.rs | 29 +++++++++++---------- src/cli/clean.rs | 33 +++++++++++------------- src/cli/flag_update.rs | 9 ++++--- src/cli/fmt.rs | 17 +++++++------ src/cli/gen.rs | 19 +++++++------- src/cli/help.rs | 23 +++++++++-------- src/cli/init.rs | 32 +++++++++++------------ src/cli/lint.rs | 25 ++++++++++-------- src/cli/new.rs | 45 ++++++++++++++++----------------- src/cli/run.rs | 21 ++++++++-------- src/cli/setup.rs | 9 ++++--- src/cli/test.rs | 56 +++++++++++++++++++++++------------------ src/cli/tree.rs | 11 ++++---- src/utils/cli_styles.rs | 48 ++++++++++++++--------------------- 15 files changed, 201 insertions(+), 195 deletions(-) diff --git a/src/cli/add.rs b/src/cli/add.rs index 747538b..7ab87db 100644 --- a/src/cli/add.rs +++ b/src/cli/add.rs @@ -18,8 +18,9 @@ use crate::prelude::*; use crate::core::{build_config::Config, deps::register}; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::cli_styles::{Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST}; use crate::utils::fs::find_project_root; +use crate::utils::log::sprintln; use toml::{Value, map::Map}; /// Parsed arguments for the `dcr add` command. @@ -58,16 +59,16 @@ pub struct AddArgs { /// Process exit code: `0` on success, non-zero on usage or I/O errors. pub fn add(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc( - " dcr add [--branch ] [--tag ] [--rev ]", - BOLD_CYAN, + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!( + HELP_EXAMPLES_ST, + " dcr add [--branch ] [--tag ] [--rev ]" ); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Adds a dependency to the project."); println!(); - printc("SOURCES:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "SOURCES:"); println!(" github:user/repo GitHub repository"); println!(" gitlab:user/repo GitLab repository"); println!(" git:host.com/user/repo Generic git repository"); @@ -75,7 +76,7 @@ pub fn add(args: &[String]) -> i32 { println!(" pkg-config:fmt System pkg-config dependency"); println!(" Version from registry"); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --branch Use a specific branch"); println!(" --tag Use a specific tag"); println!(" --rev Use a specific commit hash"); @@ -165,7 +166,7 @@ pub fn add(args: &[String]) -> i32 { println!( " {} dependency `{}` to dcr.toml", - colored("Added", BOLD_GREEN), + "Added".style(SUCCESS_ST), add_args.name ); 0 diff --git a/src/cli/build.rs b/src/cli/build.rs index 9590e60..ab44984 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -28,8 +28,11 @@ use crate::utils::build::{ get_config_opt, get_config_str, get_language_with_profile_or_default, get_string_with_profile, normalize_kind, resolve_artifact_target_dir, resolve_compiler, }; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, BOLD_YELLOW, colored, printc}; +use crate::utils::cli_styles::{ + BOLD_CYAN, BOLD_YELLOW, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, Style, +}; use crate::utils::fs::{canonicalize_path, find_project_root}; +use crate::utils::log::sprintln; use std::io::IsTerminal; use std::path::Path; use std::sync::{Arc, atomic::AtomicBool}; @@ -37,8 +40,8 @@ use std::sync::{Arc, atomic::AtomicBool}; pub use crate::core::build::get_build_string_with_profile; /// Formats a left-aligned status verb with the given style for CLI output. -fn status(verb: &str, style: &str) -> String { - colored(&format!("{verb:<9}"), style) +fn status(verb: &str, style: Style) -> String { + format!("{verb:<9}").style(style).to_string() } /// CLI build reporter that prints human-readable progress to stderr/stdout. @@ -51,7 +54,7 @@ impl CliReporter { /// - `verb`: Short status label (e.g. `"target"`, `"dep"`). /// - `style`: Color/style constant for the verb. /// - `rest`: Remaining message text after the verb. - fn line(&self, verb: &str, style: &str, rest: &str) { + fn line(&self, verb: &str, style: Style, rest: &str) { eprintln!(" {} {}", status(verb, style), rest); } } @@ -95,12 +98,12 @@ impl BuildReporter for CliReporter { common::finish_progress_line(); // Only announce deps that were actually rebuilt this run. if rebuilt { - self.line("ready", BOLD_GREEN, &format!("{name} v{version}")); + self.line("ready", SUCCESS_ST, &format!("{name} v{version}")); } } BuildEvent::Compiling { name, version } => { common::finish_progress_line(); - let label = format!(" {} {} v{}", status("compile", BOLD_GREEN), name, version); + let label = format!(" {} {} v{}", status("compile", SUCCESS_ST), name, version); // Terminals use an in-place progress line; non-TTY gets a plain log line. common::set_progress_label(Some(label.clone())); if !std::io::stderr().is_terminal() { @@ -113,7 +116,7 @@ impl BuildReporter for CliReporter { } BuildEvent::Finished { secs } => { common::finish_progress_line(); - self.line("done", BOLD_GREEN, &format!("in {secs}s")); + self.line("done", SUCCESS_ST, &format!("in {secs}s")); } BuildEvent::CompilerOutput { stream, text } => { // Pause the progress spinner so compiler text is not overwritten. @@ -141,16 +144,16 @@ impl BuildReporter for CliReporter { /// Process exit code: `0` on success or help, non-zero on failure. pub fn build(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc( - " dcr build [--debug | --release] [--target ] [--force] [--clean] [--verbose] [--print-artifact-path]", - BOLD_CYAN, + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!( + HELP_EXAMPLES_ST, + " dcr build [--debug | --release] [--target ] [--force] [--clean] [--verbose] [--print-artifact-path]" ); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Compiles the project. Default profile is --debug."); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --debug Build with debug profile (default)"); println!(" --release Build with release profile"); println!(" --target Cross-compile for the given target"); diff --git a/src/cli/clean.rs b/src/cli/clean.rs index 233ca96..151965f 100644 --- a/src/cli/clean.rs +++ b/src/cli/clean.rs @@ -20,8 +20,11 @@ use crate::prelude::*; use crate::core::build_config::Config; use crate::core::workspace::parse_workspace; use crate::utils::build::{default_profile_flags, default_target_triple, parse_version_info}; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::cli_styles::{ + BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, +}; use crate::utils::fs::{check_dir, find_project_root, with_dir}; +use crate::utils::log::sprintln; use glob::glob; use std::{fs, path::Path}; @@ -36,16 +39,16 @@ use std::{fs, path::Path}; /// Process exit code: `0` on success, `1` on failure. pub fn clean(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc( - " dcr clean [--debug | --release] [--target ] [--all]", - BOLD_CYAN, + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!( + HELP_EXAMPLES_ST, + " dcr clean [--debug | --release] [--target ] [--all]" ); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Removes build artifacts from the target directory."); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --debug Clean debug artifacts (default)"); println!(" --release Clean release artifacts"); println!(" --target Clean artifacts for a specific target"); @@ -210,10 +213,7 @@ fn clean_project_at( if !items.contains(&"dcr.toml".to_string()) { return Err("dcr.toml file not found".to_string()); } - println!( - " Cleaning project `{}`", - colored(&project_name, BOLD_GREEN) - ); + println!(" Cleaning project `{}`", project_name.style(BOLD_GREEN)); if let Some(profile) = profile { let target_dir = if let Some(t) = target { format!("target/{t}/{profile}") @@ -231,14 +231,14 @@ fn clean_project_at( if !dir_exists { warn!("Directory target/{target_dir} not found"); } else { - println!(" Profile: {}", colored(profile, BOLD_GREEN)); + println!(" Profile: {}", profile.style(BOLD_GREEN)); if let Some(t) = target { - println!(" Target: {}", colored(t, BOLD_GREEN)); + println!(" Target: {}", t.style(BOLD_GREEN)); } let _ = fs::remove_dir_all(&target_dir); println!( "{} Removed directory {}", - colored("\n ✔", BOLD_GREEN), + "\n ✔".style(SUCCESS_ST), target_dir ); } @@ -248,10 +248,7 @@ fn clean_project_at( if items.contains(&"target".to_string()) { let _ = fs::remove_dir_all("target"); - println!( - "{} Removed directory target", - colored("\n ✔", BOLD_GREEN) - ); + println!("{} Removed directory target", "\n ✔".style(SUCCESS_ST)); } else { warn!("Directory target not found"); } diff --git a/src/cli/flag_update.rs b/src/cli/flag_update.rs index 1670b41..42b08a7 100644 --- a/src/cli/flag_update.rs +++ b/src/cli/flag_update.rs @@ -17,7 +17,8 @@ use crate::prelude::*; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, printc}; +use crate::utils::cli_styles::{HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; +use crate::utils::log::sprintln; use serde::Deserialize; use std::fs; use std::io::Read; @@ -56,10 +57,10 @@ struct ReleaseAsset { /// `0` on success / already up to date / pacman-managed refuse; `1` on error. pub fn flag_update(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr --update", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr --update"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Updates DCR to the latest version from GitHub Releases."); return 0; } diff --git a/src/cli/fmt.rs b/src/cli/fmt.rs index 82048e4..a8416b5 100644 --- a/src/cli/fmt.rs +++ b/src/cli/fmt.rs @@ -17,7 +17,10 @@ use crate::prelude::*; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::cli_styles::{ + BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, +}; +use crate::utils::log::sprintln; use glob::glob; use std::process::Command; @@ -29,10 +32,10 @@ use std::process::Command; /// If the first argument is `--help`, prints usage information and returns 0. pub fn fmt(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr fmt", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr fmt"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Formats all C/C++ source files using clang-format."); println!(" Scans src/ and tests/ directories recursively."); return 0; @@ -70,14 +73,14 @@ pub fn fmt(args: &[String]) -> i32 { } if files.is_empty() { - println!(" {} No files to format", colored("Format", BOLD_GREEN)); + println!(" {} No files to format", "Format".style(BOLD_GREEN)); return 0; } // Format the collected files println!( " {} {} files", - colored("Formatting", BOLD_GREEN), + "Formatting".style(BOLD_GREEN), files.len() ); @@ -85,7 +88,7 @@ pub fn fmt(args: &[String]) -> i32 { match status { Ok(s) if s.success() => { - println!(" {} successful", colored("Format", BOLD_GREEN)); + println!(" {} successful", "Format".style(SUCCESS_ST)); 0 } Ok(s) => { diff --git a/src/cli/gen.rs b/src/cli/gen.rs index c85e999..44b7ace 100644 --- a/src/cli/gen.rs +++ b/src/cli/gen.rs @@ -28,10 +28,11 @@ use crate::utils::build::{ get_list_with_profile, get_string_with_profile, normalize_kind, normalize_platform, resolve_artifact_target_dir, resolve_compiler, resolve_pkg_config_flags_lossy, }; +use crate::utils::cli_styles::{HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; use crate::utils::fs::{ absolute_join, atomic_write, canonicalize_path, ensure_dcr_dir, find_project_root, }; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, printc}; +use crate::utils::log::sprintln; use std::path::{Path, PathBuf}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -252,29 +253,29 @@ pub struct ProjectInfo { pub fn r#gen(args: &[String]) -> i32 { let subcommand = match args.first() { Some(s) if s == "--help" => { - printc("USAGE:", BOLD_GREEN); - printc(" dcr gen ", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr gen "); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Generates IDE and tooling integration files."); println!(); - printc("SUBCOMMANDS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "SUBCOMMANDS:"); println!(" project-info Print project metadata as JSON"); println!(" compile-commands Generate .dcr/compile_commands.json"); println!(" vscode Generate .vscode/ integration files"); println!(" clion Generate .idea/ integration files"); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --debug | --release Profile (default: debug)"); println!(" --quiet | -q Suppress success messages on stdout"); return 0; } Some(s) => s.as_str(), None => { - printc("USAGE:", BOLD_GREEN); - printc(" dcr gen ", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr gen "); println!(); - printc("SUBCOMMANDS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "SUBCOMMANDS:"); println!(" project-info Print project metadata as JSON"); println!(" compile-commands Generate .dcr/compile_commands.json"); println!(" vscode Generate .vscode/ integration files"); diff --git a/src/cli/help.rs b/src/cli/help.rs index 41bbb61..8ea8292 100644 --- a/src/cli/help.rs +++ b/src/cli/help.rs @@ -15,7 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, printc}; +use crate::utils::cli_styles::{HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; +use crate::utils::log::sprintln; /// Displays the help information for the DCR CLI tool. /// @@ -27,10 +28,10 @@ pub fn help() -> i32 { println!("DCR (Dexoron Cargo Realization)"); println!("C project manager inspired by Cargo."); println!(); - printc("USAGE:", BOLD_GREEN); - printc(" dcr [options]", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr [options]"); println!(); - printc("COMMANDS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "COMMANDS:"); println!(" new Create a new project"); println!(" init Initialize the current directory as a project"); println!(" build [--profile] Build the project (default: --debug)"); @@ -43,24 +44,24 @@ pub fn help() -> i32 { println!(" setup Show configured package registries"); println!(" clean Remove the target directory"); println!(" gen Generate IDE integration files"); - printc("FLAGS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "FLAGS:"); println!(" --help Show command help"); println!(" --update Update dcr to the latest version"); println!(" --version Show dcr version"); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --debug Use debug profile"); println!(" --release Use release profile"); println!(" --force Force rebuild (build/run)"); println!(" --clean Clean before build (build/run)"); println!(" --all Clean all workspace members (clean)"); println!(); - printc("EXAMPLES:", BOLD_GREEN); - printc(" dcr new hello", BOLD_CYAN); - printc(" dcr build --release", BOLD_CYAN); - printc(" dcr run --debug", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "EXAMPLES:"); + sprintln!(HELP_EXAMPLES_ST, " dcr new hello"); + sprintln!(HELP_EXAMPLES_ST, " dcr build --release"); + sprintln!(HELP_EXAMPLES_ST, " dcr run --debug"); println!(); - printc("TIP:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "TIP:"); println!(" Run 'dcr --help' for command-specific help."); 0 } diff --git a/src/cli/init.rs b/src/cli/init.rs index 7bb28f6..082773f 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -20,8 +20,11 @@ use crate::prelude::*; use crate::config::FILE_MAIN_C; use crate::core::build_config::{Config, validate_package_name}; use crate::core::vcs::VcsKind; +use crate::utils::cli_styles::{ + BOLD_CYAN, BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, +}; use crate::utils::fs::check_dir; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::log::sprintln; use std::{fs, io::Write}; /// Initializes the current working directory as a new DCR project. @@ -30,10 +33,10 @@ use std::{fs, io::Write}; /// `dcr.toml` and `src/main.c`, and configures version control (Git) integration if applicable. pub fn init(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr init [--vcs ]", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr init [--vcs ]"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Initializes the current directory as a DCR project."); println!(" The directory must be empty."); return 0; @@ -78,7 +81,7 @@ pub fn init(args: &[String]) -> i32 { if let Err(e) = validate_package_name(&project_name) { error!( "Invalid project name `{}`: {e}", - colored(&project_name, BOLD_CYAN), + project_name.style(BOLD_CYAN), ); return 1; } @@ -95,8 +98,8 @@ pub fn init(args: &[String]) -> i32 { } println!( " {} Created file {}", - colored("✔", BOLD_GREEN), - colored("dcr.toml", BOLD_CYAN) + "✔".style(SUCCESS_ST), + "dcr.toml".style(BOLD_CYAN) ); // Create src directory and write template main.c file. @@ -117,8 +120,8 @@ pub fn init(args: &[String]) -> i32 { } println!( " {} Created file {}", - colored("✔", BOLD_GREEN), - colored("src/main.c", BOLD_CYAN) + "✔".style(SUCCESS_ST), + "src/main.c".style(BOLD_CYAN) ); // Resolve target VCS provider or detect existing repositories. @@ -143,10 +146,7 @@ pub fn init(args: &[String]) -> i32 { if let Err(e) = crate::core::vcs::init_vcs(vcs_kind, project_path) { warn!("Failed to initialize git repository: {e}"); } else { - println!( - " {} Initialized git repository", - colored("✔", BOLD_GREEN) - ); + println!(" {} Initialized git repository", "✔".style(SUCCESS_ST)); } } else { warn!( @@ -161,9 +161,9 @@ pub fn init(args: &[String]) -> i32 { println!( "Project `{}` successfully created\n", - colored(project_name.as_str(), BOLD_GREEN) + project_name.style(SUCCESS_ST) ); - printc("Next step:", BOLD_GREEN); - printc(" dcr run", BOLD_CYAN); + sprintln!(BOLD_GREEN, "Next step:"); + sprintln!(BOLD_CYAN, " dcr run"); 0 } diff --git a/src/cli/lint.rs b/src/cli/lint.rs index 557766b..097fcb7 100644 --- a/src/cli/lint.rs +++ b/src/cli/lint.rs @@ -20,8 +20,11 @@ use crate::prelude::*; use crate::core::build::common; use crate::core::build_config::Config; use crate::utils::build::{get_bool_with_profile, get_list_with_profile}; +use crate::utils::cli_styles::{ + ALERT_ST, BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, +}; use crate::utils::fs::find_project_root; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, BOLD_YELLOW, colored, printc}; +use crate::utils::log::sprintln; use std::path::{Path, PathBuf}; use std::process::Command; @@ -30,14 +33,14 @@ use std::process::Command; /// Scans source roots (configurable via build.roots) and tests/ directory. pub fn lint(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr lint [--fix]", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr lint [--fix]"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Runs clang-tidy on all C/C++ source files."); println!(" Scans source roots (configurable via build.roots) and tests/ directory."); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --fix Apply clang-tidy suggestions automatically"); return 0; } @@ -117,13 +120,13 @@ pub fn lint(args: &[String]) -> i32 { files.sort(); if files.is_empty() { - println!(" {} No files to lint", colored("Lint", BOLD_GREEN)); + println!(" {} No files to lint", "Lint".style(BOLD_GREEN)); return 0; } println!( " {} {} files {}", - colored("Linting", BOLD_GREEN), + "Linting".style(BOLD_GREEN), files.len(), if do_fix { "(with --fix)" } else { "" } ); @@ -161,13 +164,13 @@ pub fn lint(args: &[String]) -> i32 { if issue_count > 0 { total_issues += issue_count as u32; failed += 1; - print!(" {} ", colored("×", BOLD_YELLOW)); + print!(" {} ", "×".style(ALERT_ST)); println!("{} ({} issues)", file, issue_count); for issue in &issues { println!(" {}", issue); } } else { - print!(" {} ", colored("✓", BOLD_GREEN)); + print!(" {} ", "✓".style(SUCCESS_ST)); println!("{}", file); } } @@ -178,13 +181,13 @@ pub fn lint(args: &[String]) -> i32 { if failed == 0 { println!( " {} {} files, no issues", - colored("Lint", BOLD_GREEN), + "Lint".style(SUCCESS_ST), total ); } else { println!( " {} {}/{} files passed, {} issues found", - colored("Lint", BOLD_YELLOW), + "Lint".style(ALERT_ST), passed, total, total_issues diff --git a/src/cli/new.rs b/src/cli/new.rs index 369bf0a..2f4bc1d 100644 --- a/src/cli/new.rs +++ b/src/cli/new.rs @@ -20,8 +20,11 @@ use crate::prelude::*; use crate::config::FILE_MAIN_C; use crate::core::build_config::{Config, validate_package_name}; use crate::core::vcs::VcsKind; +use crate::utils::cli_styles::{ + BOLD_CYAN, BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SUCCESS_ST, +}; use crate::utils::fs::check_dir; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::log::sprintln; use std::{fs, io::Write}; /// Executes the `dcr new` command to scaffold a new C/C++ project directory structure. @@ -30,10 +33,10 @@ use std::{fs, io::Write}; /// template source file generation (`src/main.c`), and initial VCS setup. pub fn new(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr new [--vcs ]", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr new [--vcs ]"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Creates a new C/C++ project with the given name."); println!(" The name may only contain ASCII letters, digits, '_' and '-'."); return 0; @@ -70,15 +73,12 @@ pub fn new(args: &[String]) -> i32 { } let project_name = &clean_args[0]; - println!( - "Creating a Project `{}`...", - colored(project_name, BOLD_CYAN) - ); + println!("Creating a Project `{}`...", project_name.style(BOLD_CYAN)); if let Err(e) = validate_package_name(project_name) { error!( "Invalid project name `{}`: {e}", - colored(project_name, BOLD_CYAN), + project_name.style(BOLD_CYAN), ); return 1; } @@ -86,12 +86,12 @@ pub fn new(args: &[String]) -> i32 { if items.contains(project_name) { error!( "Directory `{}` already exists\n", - colored(project_name, BOLD_CYAN) + project_name.style(BOLD_CYAN) ); - printc("Hint:", BOLD_CYAN); + sprintln!(BOLD_CYAN, "Hint:"); println!( " Use `{}` to initialize an existing project\n or specify a different project name", - colored("dcr init", BOLD_CYAN) + "dcr init".style(BOLD_CYAN) ); return 1; } @@ -102,7 +102,7 @@ pub fn new(args: &[String]) -> i32 { } println!( " {} Directory created {}", - colored("✔", BOLD_GREEN), + "✔".style(SUCCESS_ST), project_name ); @@ -114,8 +114,8 @@ pub fn new(args: &[String]) -> i32 { } println!( " {} Created file {}", - colored("✔", BOLD_GREEN), - colored("dcr.toml", BOLD_CYAN) + "✔".style(SUCCESS_ST), + "dcr.toml".style(BOLD_CYAN) ); // Generate src directory and populate initial main.c file. @@ -137,8 +137,8 @@ pub fn new(args: &[String]) -> i32 { } println!( " {} Created file {}", - colored("✔", BOLD_GREEN), - colored("src/main.c", BOLD_CYAN) + "✔".style(SUCCESS_ST), + "src/main.c".style(BOLD_CYAN) ); // Resolve target VCS mode based on CLI flags or parent directory state. @@ -164,10 +164,7 @@ pub fn new(args: &[String]) -> i32 { if let Err(e) = crate::core::vcs::init_vcs(vcs_kind, project_path) { warn!("Failed to initialize git repository: {e}"); } else { - println!( - " {} Initialized git repository", - colored("✔", BOLD_GREEN) - ); + println!(" {} Initialized git repository", "✔".style(SUCCESS_ST)); } } else { warn!( @@ -183,9 +180,9 @@ pub fn new(args: &[String]) -> i32 { println!( "Project `{}` successfully created\n", - colored(project_name, BOLD_GREEN) + project_name.style(SUCCESS_ST) ); - printc("Next step:", BOLD_GREEN); - printc(&format!(" cd {}\n dcr run", project_name), BOLD_CYAN); + sprintln!(BOLD_GREEN, "Next step:"); + sprintln!(BOLD_CYAN, " cd {}\n dcr run", project_name); 0 } diff --git a/src/cli/run.rs b/src/cli/run.rs index 78c08bf..a8f553e 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -22,8 +22,9 @@ use crate::cli::flags::parse_build_run_flags; use crate::core::build_config::Config; use crate::core::runner::run_binary; use crate::utils::build::{normalize_target_os, parse_version_info, substitute_vars}; +use crate::utils::cli_styles::{BOLD_GREEN, Colorize, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; use crate::utils::fs::{find_project_root, with_dir}; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, colored, printc}; +use crate::utils::log::sprintln; use std::{path::Path, process::Command}; /// Retrieves the run command from the config, preferring target-specific, @@ -66,17 +67,17 @@ fn get_run_cmd( /// Process exit code from the built binary / `run.cmd`, or non-zero on build/setup failure. pub fn run(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc( - " dcr run [--debug | --release] [--target ] [--force] [--clean] [--verbose] [-- ...]", - BOLD_CYAN, + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!( + HELP_EXAMPLES_ST, + " dcr run [--debug | --release] [--target ] [--force] [--clean] [--verbose] [-- ...]" ); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Builds and runs the project. Only available for kind = \"bin\"."); println!(" Arguments after `--` are passed to the built binary (cargo-style)."); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --debug Run with debug profile (default)"); println!(" --release Run with release profile"); println!(" --target Cross-compile for the given target"); @@ -127,7 +128,7 @@ pub fn run(args: &[String]) -> i32 { let display = display_run_cmd(&cmd, &flags.bin_args); println!( " {} {}", - colored(&format!("{:<9}", "run"), BOLD_GREEN), + format!("{:<9}", "run").style(BOLD_GREEN), display ); return run_shell_with_args(&cmd, &flags.bin_args); @@ -267,7 +268,7 @@ fn run_project( let display = display_run_cmd(&cmd, &flags.bin_args); println!( " {} {}", - colored(&format!("{:<9}", "run"), BOLD_GREEN), + format!("{:<9}", "run").style(BOLD_GREEN), display ); return Ok(run_shell_with_args(&cmd, &flags.bin_args)); @@ -275,7 +276,7 @@ fn run_project( let display = display_bin_run(&bin_path, &flags.bin_args); println!( " {} {}", - colored(&format!("{:<9}", "run"), BOLD_GREEN), + format!("{:<9}", "run").style(BOLD_GREEN), display ); return Ok(run_binary( diff --git a/src/cli/setup.rs b/src/cli/setup.rs index 37f428a..f2f65b5 100644 --- a/src/cli/setup.rs +++ b/src/cli/setup.rs @@ -15,15 +15,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, printc}; +use crate::utils::cli_styles::{HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; +use crate::utils::log::sprintln; /// Sets up DCR registries by loading the registry manager and printing the list of registries. pub fn setup(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr setup", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr setup"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Sets up DCR registries. Downloads and indexes"); println!(" package registries for dependency resolution."); return 0; diff --git a/src/cli/test.rs b/src/cli/test.rs index d7e20d7..14c3d35 100644 --- a/src/cli/test.rs +++ b/src/cli/test.rs @@ -24,30 +24,35 @@ use crate::utils::build::{ get_config_opt, get_config_str, get_language_with_profile, get_list_with_profile, get_string_with_profile, resolve_compiler, resolve_pkg_config_flags, }; +use crate::utils::cli_styles::{ + BOLD_GREEN, Colorize, ERROR_ST, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST, SKIP_ST, SUCCESS_ST, + Style, +}; use crate::utils::fs::{find_project_root, with_dir}; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, BOLD_RED, RESET, colored, printc}; +use crate::utils::log::sprintln; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -const BOLD_BLUE: &str = "\x1b[1m\x1b[94m"; - /// Runs project tests and prints a unified testsuite report. pub fn test(args: &[String]) -> i32 { let mut init_header = false; let mut profile = "debug"; for arg in args { if arg == "--help" { - printc("USAGE:", BOLD_GREEN); - printc(" dcr test [--init] [--debug | --release]", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!( + HELP_EXAMPLES_ST, + " dcr test [--init] [--debug | --release]" + ); println!(); - printc("ALIASES:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "ALIASES:"); println!(" dcr tests"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Runs project tests and prints a unified testsuite report."); println!(); - printc("OPTIONS:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "OPTIONS:"); println!(" --init Create tests/dcr_test.h in current project"); println!(" --debug Build and run tests with debug profile (default)"); println!(" --release Build and run tests with release profile"); @@ -195,19 +200,19 @@ fn run_testsuite(profile: &str) -> Result { for line in stdout.lines() { let line = line.trim(); if let Some(name) = line.strip_prefix("[PASS] ") { - println!("{} {}", colored("[PASS]", BOLD_GREEN), name); + println!("{} {}", "[PASS]".style(SUCCESS_ST), name); pass += 1; parsed_any = true; continue; } if let Some(name) = line.strip_prefix("[SKIP] ") { - println!("{} {}", colored("[SKIP]", BOLD_BLUE), name); + println!("{} {}", "[SKIP]".style(SKIP_ST), name); skip += 1; parsed_any = true; continue; } if let Some(name) = line.strip_prefix("[FAIL] ") { - println!("{} {}", colored("[FAIL]", BOLD_RED), name); + println!("{} {}", "[FAIL]".style(ERROR_ST), name); fail += 1; parsed_any = true; continue; @@ -215,17 +220,17 @@ fn run_testsuite(profile: &str) -> Result { if let Some((status, name)) = line.split_once('\t') { match status { "PASS" => { - println!("{} {}", colored("[PASS]", BOLD_GREEN), name); + println!("{} {}", "[PASS]".style(SUCCESS_ST), name); pass += 1; parsed_any = true; } "SKIP" => { - println!("{} {}", colored("[SKIP]", BOLD_BLUE), name); + println!("{} {}", "[SKIP]".style(SKIP_ST), name); skip += 1; parsed_any = true; } "FAIL" => { - println!("{} {}", colored("[FAIL]", BOLD_RED), name); + println!("{} {}", "[FAIL]".style(ERROR_ST), name); fail += 1; parsed_any = true; } @@ -237,11 +242,11 @@ fn run_testsuite(profile: &str) -> Result { if !parsed_any { if suite_success { for name in &declared { - println!("{} {}", colored("[PASS]", BOLD_GREEN), name); + println!("{} {}", "[PASS]".style(SUCCESS_ST), name); } pass = declared.len() as i32; } else { - println!("{} testsuite", colored("[FAIL]", BOLD_RED)); + println!("{} testsuite", "[FAIL]".style(ERROR_ST)); fail = 1; } } @@ -253,14 +258,15 @@ fn run_testsuite(profile: &str) -> Result { }; println!(); - println!("{}", colored("=====================", BOLD_GREEN)); - println!("{}", colored(" Testsuite summary ", BOLD_GREEN)); - println!("{}", colored("=====================", BOLD_GREEN)); + sprintln!(BOLD_GREEN, "====================="); + sprintln!(BOLD_GREEN, " Testsuite summary "); + sprintln!(BOLD_GREEN, "====================="); println!("TOTAL: {}", total); - print_field("PASS", pass, BOLD_GREEN); - print_field("SKIP", skip, BOLD_BLUE); - print_field("FAIL", fail, BOLD_RED); - println!("{}", colored("=====================", BOLD_GREEN)); + print_field("PASS", pass, SUCCESS_ST); + print_field("SKIP", skip, SKIP_ST); + print_field("FAIL", fail, ERROR_ST); + sprintln!(BOLD_GREEN, "====================="); + sprintln!(BOLD_GREEN, "====================="); if fail > 0 || !suite_success { return Ok(1); @@ -395,10 +401,10 @@ fn extract_test_names_path(path: &Path) -> Vec { } /// Prints a test result field with color coding. -fn print_field(label: &str, value: i32, color: &str) { +fn print_field(label: &str, value: i32, style: Style) { if value == 0 { println!("{}: {}", label, value); } else { - println!("{}{}: {}{}", color, label, value, RESET); + sprintln!(style, "{}: {}", label, value); } } diff --git a/src/cli/tree.rs b/src/cli/tree.rs index 615c545..908e867 100644 --- a/src/cli/tree.rs +++ b/src/cli/tree.rs @@ -18,7 +18,8 @@ use crate::prelude::*; use crate::core::build_config::Config; -use crate::utils::cli_styles::{BOLD_CYAN, BOLD_GREEN, printc}; +use crate::utils::cli_styles::{BOLD_CYAN, HELP_EXAMPLES_ST, HELP_SECTION_TITLE_ST}; +use crate::utils::log::sprintln; use std::collections::HashSet; use std::path::{Path, PathBuf}; use toml::Value; @@ -29,10 +30,10 @@ use toml::Value; /// Otherwise, it parses the dcr.toml configuration and prints the dependency tree. pub fn tree(args: &[String]) -> i32 { if args.first().is_some_and(|a| a == "--help") { - printc("USAGE:", BOLD_GREEN); - printc(" dcr tree", BOLD_CYAN); + sprintln!(HELP_SECTION_TITLE_ST, "USAGE:"); + sprintln!(HELP_EXAMPLES_ST, " dcr tree"); println!(); - printc("DESCRIPTION:", BOLD_GREEN); + sprintln!(HELP_SECTION_TITLE_ST, "DESCRIPTION:"); println!(" Displays the dependency tree of the current project."); return 0; } @@ -55,7 +56,7 @@ pub fn tree(args: &[String]) -> i32 { .and_then(|v| v.as_str()) .unwrap_or("0.0.0"); - printc(&format!("{} v{}", name, version), BOLD_CYAN); + sprintln!(BOLD_CYAN, "{} v{}", name, version); let mut seen = HashSet::new(); seen.insert(name.to_string()); diff --git a/src/utils/cli_styles.rs b/src/utils/cli_styles.rs index f63b38f..5eabd84 100644 --- a/src/utils/cli_styles.rs +++ b/src/utils/cli_styles.rs @@ -15,43 +15,33 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#[allow(unused_imports)] pub use owo_colors::{OwoColorize as Colorize, Style}; // Сli theme styles +// Main #[allow(dead_code)] -pub const RESET: &str = "\x1b[0m"; +pub const BOLD_RED: Style = Style::new().bright_red().bold(); +#[allow(dead_code)] +pub const BOLD_GREEN: Style = Style::new().bright_green().bold(); +#[allow(dead_code)] +pub const BOLD_YELLOW: Style = Style::new().bright_yellow().bold(); +#[allow(dead_code)] +pub const BOLD_CYAN: Style = Style::new().bright_cyan().bold(); +#[allow(dead_code)] +pub const BOLD_BLUE: Style = Style::new().bright_blue().bold(); +// Help #[allow(dead_code)] -pub const BOLD: &str = "\x1b[1m"; +pub const HELP_SECTION_TITLE_ST: Style = BOLD_GREEN; +#[allow(dead_code)] +pub const HELP_EXAMPLES_ST: Style = BOLD_CYAN; +// Other #[allow(dead_code)] -pub const BRIGHT_RED: &str = "\x1b[91m"; +pub const ERROR_ST: Style = BOLD_RED; #[allow(dead_code)] -pub const BRIGHT_GREEN: &str = "\x1b[92m"; +pub const SUCCESS_ST: Style = BOLD_GREEN; #[allow(dead_code)] -pub const BRIGHT_YELLOW: &str = "\x1b[93m"; +pub const ALERT_ST: Style = BOLD_YELLOW; #[allow(dead_code)] -pub const BRIGHT_CYAN: &str = "\x1b[96m"; -#[allow(dead_code)] -pub const BOLD_RED: &str = "\x1b[1m\x1b[91m"; -#[allow(dead_code)] -pub const BOLD_GREEN: &str = "\x1b[1m\x1b[92m"; -#[allow(dead_code)] -pub const BOLD_YELLOW: &str = "\x1b[1m\x1b[93m"; -#[allow(dead_code)] -pub const BOLD_CYAN: &str = "\x1b[1m\x1b[96m"; - -/// Applies ANSI escape codes to format the message with the given style. -/// -/// This is a utility for colored output in terminal applications. -#[allow(dead_code)] -pub fn colored(msg: &str, style: &str) -> String { - format!("{style}{msg}{RESET}") -} - -/// Prints `msg` to stdout with the given ANSI `style`. -#[allow(dead_code)] -pub fn printc(msg: &str, style: &str) { - println!("{style}{msg}{RESET}"); -} +pub const SKIP_ST: Style = BOLD_BLUE;