feat: add NO_COLOR environment variable support (#122)
Add a centralized color module (cli/src/color.rs) that respects the NO_COLOR environment variable per https://no-color.org/ Changes: - Add color.rs module with helper functions for colored output - Refactor all hardcoded ANSI escape codes to use the color module - Add tests for color formatting functions - Update AGENTS.md with color module usage guidelines Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
28740acecf
commit
c88734da89
@@ -5,6 +5,7 @@ Instructions for AI coding agents working with this codebase.
|
|||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
- Do not use emojis in code, output, or documentation. Unicode symbols (✓, ✗, →, ⚠) are acceptable.
|
- Do not use emojis in code, output, or documentation. Unicode symbols (✓, ✗, →, ⚠) are acceptable.
|
||||||
|
- CLI colored output uses `cli/src/color.rs`. This module respects the `NO_COLOR` environment variable. Never use hardcoded ANSI color codes.
|
||||||
|
|
||||||
<!-- opensrc:start -->
|
<!-- opensrc:start -->
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
//! Color output utilities respecting NO_COLOR environment variable.
|
||||||
|
//!
|
||||||
|
//! When the NO_COLOR environment variable is present (regardless of value),
|
||||||
|
//! all color formatting is disabled per https://no-color.org/
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
/// Returns true if color output is enabled (NO_COLOR is NOT set)
|
||||||
|
pub fn is_enabled() -> bool {
|
||||||
|
static COLORS_ENABLED: OnceLock<bool> = OnceLock::new();
|
||||||
|
*COLORS_ENABLED.get_or_init(|| env::var("NO_COLOR").is_err())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in red (errors)
|
||||||
|
pub fn red(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[31m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in green (success)
|
||||||
|
pub fn green(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[32m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in yellow (warnings)
|
||||||
|
pub fn yellow(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[33m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in cyan (info/progress)
|
||||||
|
pub fn cyan(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[36m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in bold
|
||||||
|
pub fn bold(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[1m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format text in dim
|
||||||
|
pub fn dim(text: &str) -> String {
|
||||||
|
if is_enabled() {
|
||||||
|
format!("\x1b[2m{}\x1b[0m", text)
|
||||||
|
} else {
|
||||||
|
text.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Red X error indicator
|
||||||
|
pub fn error_indicator() -> &'static str {
|
||||||
|
static INDICATOR: OnceLock<String> = OnceLock::new();
|
||||||
|
INDICATOR.get_or_init(|| {
|
||||||
|
if is_enabled() {
|
||||||
|
"\x1b[31m✗\x1b[0m".to_string()
|
||||||
|
} else {
|
||||||
|
"✗".to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Green checkmark success indicator
|
||||||
|
pub fn success_indicator() -> &'static str {
|
||||||
|
static INDICATOR: OnceLock<String> = OnceLock::new();
|
||||||
|
INDICATOR.get_or_init(|| {
|
||||||
|
if is_enabled() {
|
||||||
|
"\x1b[32m✓\x1b[0m".to_string()
|
||||||
|
} else {
|
||||||
|
"✓".to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Yellow warning indicator
|
||||||
|
pub fn warning_indicator() -> &'static str {
|
||||||
|
static INDICATOR: OnceLock<String> = OnceLock::new();
|
||||||
|
INDICATOR.get_or_init(|| {
|
||||||
|
if is_enabled() {
|
||||||
|
"\x1b[33m⚠\x1b[0m".to_string()
|
||||||
|
} else {
|
||||||
|
"⚠".to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get console log color prefix by level
|
||||||
|
pub fn console_level_prefix(level: &str) -> String {
|
||||||
|
if !is_enabled() {
|
||||||
|
return format!("[{}]", level);
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = match level {
|
||||||
|
"error" => "\x1b[31m",
|
||||||
|
"warning" => "\x1b[33m",
|
||||||
|
"info" => "\x1b[36m",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
if color.is_empty() {
|
||||||
|
format!("[{}]", level)
|
||||||
|
} else {
|
||||||
|
format!("{}[{}]\x1b[0m", color, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_red_contains_ansi_codes() {
|
||||||
|
// Test the format structure (actual color depends on NO_COLOR env)
|
||||||
|
let formatted = format!("\x1b[31m{}\x1b[0m", "error");
|
||||||
|
assert!(formatted.contains("\x1b[31m"));
|
||||||
|
assert!(formatted.contains("\x1b[0m"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_green_contains_ansi_codes() {
|
||||||
|
let formatted = format!("\x1b[32m{}\x1b[0m", "success");
|
||||||
|
assert!(formatted.contains("\x1b[32m"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_console_level_prefix_contains_level() {
|
||||||
|
// Regardless of color state, the level text should be present
|
||||||
|
assert!(console_level_prefix("error").contains("error"));
|
||||||
|
assert!(console_level_prefix("warning").contains("warning"));
|
||||||
|
assert!(console_level_prefix("info").contains("info"));
|
||||||
|
assert!(console_level_prefix("log").contains("log"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indicators_contain_symbols() {
|
||||||
|
// Regardless of color state, symbols should be present
|
||||||
|
assert!(error_indicator().contains('✗'));
|
||||||
|
assert!(success_indicator().contains('✓'));
|
||||||
|
assert!(warning_indicator().contains('⚠'));
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-12
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::color;
|
||||||
use std::process::{exit, Command, Stdio};
|
use std::process::{exit, Command, Stdio};
|
||||||
|
|
||||||
pub fn run_install(with_deps: bool) {
|
pub fn run_install(with_deps: bool) {
|
||||||
@@ -5,7 +6,7 @@ pub fn run_install(with_deps: bool) {
|
|||||||
|
|
||||||
if is_linux {
|
if is_linux {
|
||||||
if with_deps {
|
if with_deps {
|
||||||
println!("\x1b[36mInstalling system dependencies...\x1b[0m");
|
println!("{}", color::cyan("Installing system dependencies..."));
|
||||||
|
|
||||||
let (pkg_mgr, deps) = if which_exists("apt-get") {
|
let (pkg_mgr, deps) = if which_exists("apt-get") {
|
||||||
(
|
(
|
||||||
@@ -93,7 +94,7 @@ pub fn run_install(with_deps: bool) {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m No supported package manager found (apt-get, dnf, or yum)");
|
eprintln!("{} No supported package manager found (apt-get, dnf, or yum)", color::error_indicator());
|
||||||
exit(1);
|
exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,22 +113,23 @@ pub fn run_install(with_deps: bool) {
|
|||||||
|
|
||||||
match status {
|
match status {
|
||||||
Ok(s) if s.success() => {
|
Ok(s) if s.success() => {
|
||||||
println!("\x1b[32m✓\x1b[0m System dependencies installed")
|
println!("{} System dependencies installed", color::success_indicator())
|
||||||
}
|
}
|
||||||
Ok(_) => eprintln!(
|
Ok(_) => eprintln!(
|
||||||
"\x1b[33m⚠\x1b[0m Failed to install some dependencies. You may need to run manually with sudo."
|
"{} Failed to install some dependencies. You may need to run manually with sudo.",
|
||||||
|
color::warning_indicator()
|
||||||
),
|
),
|
||||||
Err(e) => eprintln!("\x1b[33m⚠\x1b[0m Could not run install command: {}", e),
|
Err(e) => eprintln!("{} Could not run install command: {}", color::warning_indicator(), e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("\x1b[33m⚠\x1b[0m Linux detected. If browser fails to launch, run:");
|
println!("{} Linux detected. If browser fails to launch, run:", color::warning_indicator());
|
||||||
println!(" agent-browser install --with-deps");
|
println!(" agent-browser install --with-deps");
|
||||||
println!(" or: npx playwright install-deps chromium");
|
println!(" or: npx playwright install-deps chromium");
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\x1b[36mInstalling Chromium browser...\x1b[0m");
|
println!("{}", color::cyan("Installing Chromium browser..."));
|
||||||
|
|
||||||
// On Windows, we need to use cmd.exe to run npx because npx is actually npx.cmd
|
// On Windows, we need to use cmd.exe to run npx because npx is actually npx.cmd
|
||||||
// and Command::new() doesn't resolve .cmd files the way the shell does.
|
// and Command::new() doesn't resolve .cmd files the way the shell does.
|
||||||
@@ -144,23 +146,23 @@ pub fn run_install(with_deps: bool) {
|
|||||||
|
|
||||||
match status {
|
match status {
|
||||||
Ok(s) if s.success() => {
|
Ok(s) if s.success() => {
|
||||||
println!("\x1b[32m✓\x1b[0m Chromium installed successfully");
|
println!("{} Chromium installed successfully", color::success_indicator());
|
||||||
if is_linux && !with_deps {
|
if is_linux && !with_deps {
|
||||||
println!();
|
println!();
|
||||||
println!("\x1b[33mNote:\x1b[0m If you see \"shared library\" errors when running, use:");
|
println!("{} If you see \"shared library\" errors when running, use:", color::yellow("Note:"));
|
||||||
println!(" agent-browser install --with-deps");
|
println!(" agent-browser install --with-deps");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m Failed to install browser");
|
eprintln!("{} Failed to install browser", color::error_indicator());
|
||||||
if is_linux {
|
if is_linux {
|
||||||
println!("\x1b[33mTip:\x1b[0m Try installing system dependencies first:");
|
println!("{} Try installing system dependencies first:", color::yellow("Tip:"));
|
||||||
println!(" agent-browser install --with-deps");
|
println!(" agent-browser install --with-deps");
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m Failed to run npx: {}", e);
|
eprintln!("{} Failed to run npx: {}", color::error_indicator(), e);
|
||||||
eprintln!("Make sure Node.js is installed and npx is in your PATH");
|
eprintln!("Make sure Node.js is installed and npx is in your PATH");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-11
@@ -1,3 +1,4 @@
|
|||||||
|
mod color;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod connection;
|
mod connection;
|
||||||
mod flags;
|
mod flags;
|
||||||
@@ -107,7 +108,7 @@ fn run_session(args: &[String], session: &str, json_mode: bool) {
|
|||||||
} else {
|
} else {
|
||||||
println!("Active sessions:");
|
println!("Active sessions:");
|
||||||
for s in &sessions {
|
for s in &sessions {
|
||||||
let marker = if s == session { "→" } else { " " };
|
let marker = if s == session { color::cyan("→") } else { " ".to_string() };
|
||||||
println!("{} {}", marker, s);
|
println!("{} {}", marker, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +180,7 @@ fn main() {
|
|||||||
error_type
|
error_type
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m{}\x1b[0m", e.format());
|
eprintln!("{}", color::red(&e.format()));
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -191,7 +192,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, e);
|
println!(r#"{{"success":false,"error":"{}"}}"#, e);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", e);
|
eprintln!("{} {}", color::error_indicator(), e);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -201,10 +202,10 @@ fn main() {
|
|||||||
if daemon_result.already_running && (flags.executable_path.is_some() || !flags.extensions.is_empty()) {
|
if daemon_result.already_running && (flags.executable_path.is_some() || !flags.extensions.is_empty()) {
|
||||||
if !flags.json {
|
if !flags.json {
|
||||||
if flags.executable_path.is_some() {
|
if flags.executable_path.is_some() {
|
||||||
eprintln!("\x1b[33m⚠\x1b[0m --executable-path ignored: daemon already running. Use 'agent-browser close' first to restart with new path.");
|
eprintln!("{} --executable-path ignored: daemon already running. Use 'agent-browser close' first to restart with new path.", color::warning_indicator());
|
||||||
}
|
}
|
||||||
if !flags.extensions.is_empty() {
|
if !flags.extensions.is_empty() {
|
||||||
eprintln!("\x1b[33m⚠\x1b[0m --extension ignored: daemon already running. Use 'agent-browser close' first to restart with extensions.");
|
eprintln!("{} --extension ignored: daemon already running. Use 'agent-browser close' first to restart with extensions.", color::warning_indicator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,7 +218,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", msg);
|
eprintln!("{} {}", color::error_indicator(), msg);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -226,7 +227,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", msg);
|
eprintln!("{} {}", color::error_indicator(), msg);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -236,7 +237,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", msg);
|
eprintln!("{} {}", color::error_indicator(), msg);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -258,7 +259,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
println!(r#"{{"success":false,"error":"{}"}}"#, msg);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", msg);
|
eprintln!("{} {}", color::error_indicator(), msg);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -281,7 +282,7 @@ fn main() {
|
|||||||
|
|
||||||
if let Err(e) = send_command(launch_cmd, &flags.session) {
|
if let Err(e) = send_command(launch_cmd, &flags.session) {
|
||||||
if !flags.json {
|
if !flags.json {
|
||||||
eprintln!("\x1b[33m⚠\x1b[0m Could not configure browser: {}", e);
|
eprintln!("{} Could not configure browser: {}", color::warning_indicator(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,7 @@ fn main() {
|
|||||||
if flags.json {
|
if flags.json {
|
||||||
println!(r#"{{"success":false,"error":"{}"}}"#, e);
|
println!(r#"{{"success":false,"error":"{}"}}"#, e);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31m✗\x1b[0m {}", e);
|
eprintln!("{} {}", color::error_indicator(), e);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-22
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::color;
|
||||||
use crate::connection::Response;
|
use crate::connection::Response;
|
||||||
|
|
||||||
pub fn print_response(resp: &Response, json_mode: bool) {
|
pub fn print_response(resp: &Response, json_mode: bool) {
|
||||||
@@ -8,7 +9,8 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
|
|
||||||
if !resp.success {
|
if !resp.success {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"\x1b[31m✗\x1b[0m {}",
|
"{} {}",
|
||||||
|
color::error_indicator(),
|
||||||
resp.error.as_deref().unwrap_or("Unknown error")
|
resp.error.as_deref().unwrap_or("Unknown error")
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -18,8 +20,8 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
// Navigation response
|
// Navigation response
|
||||||
if let Some(url) = data.get("url").and_then(|v| v.as_str()) {
|
if let Some(url) = data.get("url").and_then(|v| v.as_str()) {
|
||||||
if let Some(title) = data.get("title").and_then(|v| v.as_str()) {
|
if let Some(title) = data.get("title").and_then(|v| v.as_str()) {
|
||||||
println!("\x1b[32m✓\x1b[0m \x1b[1m{}\x1b[0m", title);
|
println!("{} {}", color::success_indicator(), color::bold(title));
|
||||||
println!("\x1b[2m {}\x1b[0m", url);
|
println!(" {}", color::dim(url));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
println!("{}", url);
|
println!("{}", url);
|
||||||
@@ -85,7 +87,7 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
.unwrap_or("Untitled");
|
.unwrap_or("Untitled");
|
||||||
let url = tab.get("url").and_then(|v| v.as_str()).unwrap_or("");
|
let url = tab.get("url").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
let active = tab.get("active").and_then(|v| v.as_bool()).unwrap_or(false);
|
let active = tab.get("active").and_then(|v| v.as_bool()).unwrap_or(false);
|
||||||
let marker = if active { "→" } else { " " };
|
let marker = if active { color::cyan("→") } else { " ".to_string() };
|
||||||
println!("{} [{}] {} - {}", marker, i, title, url);
|
println!("{} [{}] {} - {}", marker, i, title, url);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -95,13 +97,7 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
for log in logs {
|
for log in logs {
|
||||||
let level = log.get("type").and_then(|v| v.as_str()).unwrap_or("log");
|
let level = log.get("type").and_then(|v| v.as_str()).unwrap_or("log");
|
||||||
let text = log.get("text").and_then(|v| v.as_str()).unwrap_or("");
|
let text = log.get("text").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
let color = match level {
|
println!("{} {}", color::console_level_prefix(level), text);
|
||||||
"error" => "\x1b[31m",
|
|
||||||
"warning" => "\x1b[33m",
|
|
||||||
"info" => "\x1b[36m",
|
|
||||||
_ => "\x1b[0m",
|
|
||||||
};
|
|
||||||
println!("{}[{}]\x1b[0m {}", color, level, text);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -109,7 +105,7 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
if let Some(errors) = data.get("errors").and_then(|v| v.as_array()) {
|
if let Some(errors) = data.get("errors").and_then(|v| v.as_array()) {
|
||||||
for err in errors {
|
for err in errors {
|
||||||
let msg = err.get("message").and_then(|v| v.as_str()).unwrap_or("");
|
let msg = err.get("message").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
println!("\x1b[31m✗\x1b[0m {}", msg);
|
println!("{} {}", color::error_indicator(), msg);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -166,16 +162,16 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
}
|
}
|
||||||
// Closed
|
// Closed
|
||||||
if data.get("closed").is_some() {
|
if data.get("closed").is_some() {
|
||||||
println!("\x1b[32m✓\x1b[0m Browser closed");
|
println!("{} Browser closed", color::success_indicator());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Recording start (has "started" field)
|
// Recording start (has "started" field)
|
||||||
if let Some(started) = data.get("started").and_then(|v| v.as_bool()) {
|
if let Some(started) = data.get("started").and_then(|v| v.as_bool()) {
|
||||||
if started {
|
if started {
|
||||||
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording started: {}", path);
|
println!("{} Recording started: {}", color::success_indicator(), path);
|
||||||
} else {
|
} else {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording started");
|
println!("{} Recording started", color::success_indicator());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -184,9 +180,9 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
if data.get("stopped").is_some() {
|
if data.get("stopped").is_some() {
|
||||||
let path = data.get("path").and_then(|v| v.as_str()).unwrap_or("unknown");
|
let path = data.get("path").and_then(|v| v.as_str()).unwrap_or("unknown");
|
||||||
if let Some(prev_path) = data.get("previousPath").and_then(|v| v.as_str()) {
|
if let Some(prev_path) = data.get("previousPath").and_then(|v| v.as_str()) {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording restarted: {} (previous saved to {})", path, prev_path);
|
println!("{} Recording restarted: {} (previous saved to {})", color::success_indicator(), path, prev_path);
|
||||||
} else {
|
} else {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording started: {}", path);
|
println!("{} Recording started: {}", color::success_indicator(), path);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -194,18 +190,18 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
if data.get("frames").is_some() {
|
if data.get("frames").is_some() {
|
||||||
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
||||||
if let Some(error) = data.get("error").and_then(|v| v.as_str()) {
|
if let Some(error) = data.get("error").and_then(|v| v.as_str()) {
|
||||||
println!("\x1b[33m⚠\x1b[0m Recording saved to {} - {}", path, error);
|
println!("{} Recording saved to {} - {}", color::warning_indicator(), path, error);
|
||||||
} else {
|
} else {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording saved to {}", path);
|
println!("{} Recording saved to {}", color::success_indicator(), path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("\x1b[32m✓\x1b[0m Recording stopped");
|
println!("{} Recording stopped", color::success_indicator());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Screenshot path (no "started" or "frames" field)
|
// Screenshot path (no "started" or "frames" field)
|
||||||
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
||||||
println!("\x1b[32m✓\x1b[0m Screenshot saved to {}", path);
|
println!("{} Screenshot saved to {}", color::success_indicator(), color::green(path));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Screenshot base64
|
// Screenshot base64
|
||||||
@@ -214,7 +210,7 @@ pub fn print_response(resp: &Response, json_mode: bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Default success
|
// Default success
|
||||||
println!("\x1b[32m✓\x1b[0m Done");
|
println!("{} Done", color::success_indicator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user