Update 'yansi' to 1.0.0-rc.

This commit is contained in:
Sergio Benitez 2023-07-11 13:18:35 -07:00
parent 9a9cd76c01
commit c2936fcb1e
24 changed files with 119 additions and 132 deletions

View File

@ -122,10 +122,10 @@ pub trait Database: From<Self::Pool> + DerefMut<Target = Self::Pool> + Send + Sy
return Some(db); return Some(db);
} }
let dbtype = std::any::type_name::<Self>(); let dbtype = std::any::type_name::<Self>().bold().primary();
let fairing = Paint::default(format!("{}::init()", dbtype)).bold(); error!("Attempted to fetch unattached database `{}`.", dbtype);
error!("Attempted to fetch unattached database `{}`.", Paint::default(dbtype).bold()); info_!("`{}{}` fairing must be attached prior to using this database.",
info_!("`{}` fairing must be attached prior to using this database.", fairing); dbtype.linger(), "::init()".clear());
None None
} }
} }

View File

@ -59,9 +59,9 @@ impl Fairing for TemplateFairing {
let cm = rocket.state::<ContextManager>() let cm = rocket.state::<ContextManager>()
.expect("Template ContextManager registered in on_ignite"); .expect("Template ContextManager registered in on_ignite");
info!("{}{}:", Paint::emoji("📐 "), Paint::magenta("Templating")); info!("{}{}:", "📐 ".emoji(), "Templating".magenta());
info_!("directory: {}", Paint::white(Source::from(&*cm.context().root))); info_!("directory: {}", Source::from(&*cm.context().root).primary());
info_!("engines: {:?}", Paint::white(Engines::ENABLED_EXTENSIONS)); info_!("engines: {:?}", Engines::ENABLED_EXTENSIONS.primary());
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View File

@ -181,6 +181,7 @@ use rocket::response::{self, Responder};
use rocket::http::{ContentType, Status}; use rocket::http::{ContentType, Status};
use rocket::figment::{value::Value, error::Error}; use rocket::figment::{value::Value, error::Error};
use rocket::serde::Serialize; use rocket::serde::Serialize;
use rocket::yansi::Paint;
const DEFAULT_TEMPLATE_DIR: &str = "templates"; const DEFAULT_TEMPLATE_DIR: &str = "templates";
@ -441,8 +442,8 @@ impl<'r> Responder<'r, 'static> for Template {
impl Sentinel for Template { impl Sentinel for Template {
fn abort(rocket: &Rocket<Ignite>) -> bool { fn abort(rocket: &Rocket<Ignite>) -> bool {
if rocket.state::<ContextManager>().is_none() { if rocket.state::<ContextManager>().is_none() {
let template = rocket::yansi::Paint::default("Template").bold(); let template = "Template".primary().bold();
let fairing = rocket::yansi::Paint::default("Template::fairing()").bold(); let fairing = "Template::fairing()".primary().bold();
error!("returning `{}` responder without attaching `{}`.", template, fairing); error!("returning `{}` responder without attaching `{}`.", template, fairing);
info_!("To use or query templates, you must attach `{}`.", fairing); info_!("To use or query templates, you must attach `{}`.", fairing);
info_!("See the `Template` documentation for more information."); info_!("See the `Template` documentation for more information.");

View File

@ -4,6 +4,7 @@ use rocket::{Request, Rocket, Ignite, Sentinel};
use rocket::http::{Status, ContentType}; use rocket::http::{Status, ContentType};
use rocket::request::{self, FromRequest}; use rocket::request::{self, FromRequest};
use rocket::serde::Serialize; use rocket::serde::Serialize;
use rocket::yansi::Paint;
use crate::{Template, context::ContextManager}; use crate::{Template, context::ContextManager};
@ -126,8 +127,8 @@ impl Metadata<'_> {
impl Sentinel for Metadata<'_> { impl Sentinel for Metadata<'_> {
fn abort(rocket: &Rocket<Ignite>) -> bool { fn abort(rocket: &Rocket<Ignite>) -> bool {
if rocket.state::<ContextManager>().is_none() { if rocket.state::<ContextManager>().is_none() {
let md = rocket::yansi::Paint::default("Metadata").bold(); let md = "Metadata".primary().bold();
let fairing = rocket::yansi::Paint::default("Template::fairing()").bold(); let fairing = "Template::fairing()".primary().bold();
error!("requested `{}` guard without attaching `{}`.", md, fairing); error!("requested `{}` guard without attaching `{}`.", md, fairing);
info_!("To use or query templates, you must attach `{}`.", fairing); info_!("To use or query templates, you must attach `{}`.", fairing);
info_!("See the `Template` documentation for more information."); info_!("See the `Template` documentation for more information.");

View File

@ -224,10 +224,13 @@ impl<K: 'static, C: Poolable> Sentinel for Connection<K, C> {
use rocket::yansi::Paint; use rocket::yansi::Paint;
if rocket.state::<ConnectionPool<K, C>>().is_none() { if rocket.state::<ConnectionPool<K, C>>().is_none() {
let conn = Paint::default(std::any::type_name::<K>()).bold(); let conn = std::any::type_name::<K>().primary().bold();
let fairing = Paint::default(format!("{}::fairing()", conn)).wrap().bold(); error!("requesting `{}` DB connection without attaching `{}{}`.",
error!("requesting `{}` DB connection without attaching `{}`.", conn, fairing); conn, conn.linger(), "::fairing()".clear());
info_!("Attach `{}` to use database connection pooling.", fairing);
info_!("Attach `{}{}` to use database connection pooling.",
conn.linger(), "::fairing()".clear());
return true; return true;
} }

View File

@ -37,13 +37,12 @@ uuid_ = { package = "uuid", version = "1", optional = true, features = ["serde"]
# Non-optional, core dependencies from here on out. # Non-optional, core dependencies from here on out.
futures = { version = "0.3.0", default-features = false, features = ["std"] } futures = { version = "0.3.0", default-features = false, features = ["std"] }
yansi = "0.5" yansi = { version = "1.0.0-rc", features = ["detect-tty"] }
log = { version = "0.4", features = ["std"] } log = { version = "0.4", features = ["std"] }
num_cpus = "1.0" num_cpus = "1.0"
time = { version = "0.3", features = ["macros", "parsing"] } time = { version = "0.3", features = ["macros", "parsing"] }
memchr = "2" # TODO: Use pear instead. memchr = "2" # TODO: Use pear instead.
binascii = "0.1" binascii = "0.1"
is-terminal = "0.4.3"
ref-cast = "1.0" ref-cast = "1.0"
atomic = "0.5" atomic = "0.5"
parking_lot = "0.12" parking_lot = "0.12"

View File

@ -343,14 +343,14 @@ impl From<StaticInfo> for Catcher {
impl fmt::Display for Catcher { impl fmt::Display for Catcher {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref n) = self.name { if let Some(ref n) = self.name {
write!(f, "{}{}{} ", Paint::cyan("("), Paint::white(n), Paint::cyan(")"))?; write!(f, "{}{}{} ", "(".cyan(), n.primary(), ")".cyan())?;
} }
write!(f, "{} ", Paint::green(self.base.path()))?; write!(f, "{} ", self.base.path().green())?;
match self.code { match self.code {
Some(code) => write!(f, "{}", Paint::blue(code)), Some(code) => write!(f, "{}", code.blue()),
None => write!(f, "{}", Paint::blue("default")) None => write!(f, "{}", "default".blue()),
} }
} }
} }

View File

@ -4,7 +4,7 @@ use figment::{Figment, Profile, Provider, Metadata, error::Result};
use figment::providers::{Serialized, Env, Toml, Format}; use figment::providers::{Serialized, Env, Toml, Format};
use figment::value::{Map, Dict, magic::RelativePathBuf}; use figment::value::{Map, Dict, magic::RelativePathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use yansi::Paint; use yansi::{Paint, Style, Color::Primary};
use crate::log::PaintExt; use crate::log::PaintExt;
use crate::config::{LogLevel, Shutdown, Ident}; use crate::config::{LogLevel, Shutdown, Ident};
@ -383,7 +383,7 @@ impl Config {
trace!("-- configuration trace information --"); trace!("-- configuration trace information --");
for param in Self::PARAMETERS { for param in Self::PARAMETERS {
if let Some(meta) = figment.find_metadata(param) { if let Some(meta) = figment.find_metadata(param) {
let (param, name) = (Paint::blue(param), Paint::white(&meta.name)); let (param, name) = (param.blue(), meta.name.primary());
if let Some(ref source) = meta.source { if let Some(ref source) = meta.source {
trace_!("{:?} parameter source: {} ({})", param, name, source); trace_!("{:?} parameter source: {} ({})", param, name, source);
} else { } else {
@ -394,52 +394,50 @@ impl Config {
} }
pub(crate) fn pretty_print(&self, figment: &Figment) { pub(crate) fn pretty_print(&self, figment: &Figment) {
fn bold<T: std::fmt::Display>(val: T) -> Paint<T> { static VAL: Style = Primary.bold();
Paint::default(val).bold()
}
self.trace_print(figment); self.trace_print(figment);
launch_meta!("{}Configured for {}.", Paint::emoji("🔧 "), self.profile); launch_meta!("{}Configured for {}.", "🔧 ".emoji(), self.profile.underline());
launch_meta_!("address: {}", bold(&self.address)); launch_meta_!("address: {}", self.address.paint(VAL));
launch_meta_!("port: {}", bold(&self.port)); launch_meta_!("port: {}", self.port.paint(VAL));
launch_meta_!("workers: {}", bold(self.workers)); launch_meta_!("workers: {}", self.workers.paint(VAL));
launch_meta_!("max blocking threads: {}", bold(self.max_blocking)); launch_meta_!("max blocking threads: {}", self.max_blocking.paint(VAL));
launch_meta_!("ident: {}", bold(&self.ident)); launch_meta_!("ident: {}", self.ident.paint(VAL));
match self.ip_header { match self.ip_header {
Some(ref name) => launch_meta_!("IP header: {}", bold(name)), Some(ref name) => launch_meta_!("IP header: {}", name.paint(VAL)),
None => launch_meta_!("IP header: {}", bold("disabled")) None => launch_meta_!("IP header: {}", "disabled".paint(VAL))
} }
launch_meta_!("limits: {}", bold(&self.limits)); launch_meta_!("limits: {}", (&self.limits).paint(VAL));
launch_meta_!("temp dir: {}", bold(&self.temp_dir.relative().display())); launch_meta_!("temp dir: {}", self.temp_dir.relative().display().paint(VAL));
launch_meta_!("http/2: {}", bold(cfg!(feature = "http2"))); launch_meta_!("http/2: {}", (cfg!(feature = "http2").paint(VAL)));
match self.keep_alive { match self.keep_alive {
0 => launch_meta_!("keep-alive: {}", bold("disabled")), 0 => launch_meta_!("keep-alive: {}", "disabled".paint(VAL)),
ka => launch_meta_!("keep-alive: {}{}", bold(ka), bold("s")), ka => launch_meta_!("keep-alive: {}{}", ka.paint(VAL), "s".paint(VAL)),
} }
match (self.tls_enabled(), self.mtls_enabled()) { match (self.tls_enabled(), self.mtls_enabled()) {
(true, true) => launch_meta_!("tls: {}", bold("enabled w/mtls")), (true, true) => launch_meta_!("tls: {}", "enabled w/mtls".paint(VAL)),
(true, false) => launch_meta_!("tls: {} w/o mtls", bold("enabled")), (true, false) => launch_meta_!("tls: {} w/o mtls", "enabled".paint(VAL)),
(false, _) => launch_meta_!("tls: {}", bold("disabled")), (false, _) => launch_meta_!("tls: {}", "disabled".paint(VAL)),
} }
launch_meta_!("shutdown: {}", bold(&self.shutdown)); launch_meta_!("shutdown: {}", self.shutdown.paint(VAL));
launch_meta_!("log level: {}", bold(self.log_level)); launch_meta_!("log level: {}", self.log_level.paint(VAL));
launch_meta_!("cli colors: {}", bold(&self.cli_colors)); launch_meta_!("cli colors: {}", self.cli_colors.paint(VAL));
// Check for now deprecated config values. // Check for now deprecated config values.
for (key, replacement) in Self::DEPRECATED_KEYS { for (key, replacement) in Self::DEPRECATED_KEYS {
if let Some(md) = figment.find_metadata(key) { if let Some(md) = figment.find_metadata(key) {
warn!("found value for deprecated config key `{}`", Paint::white(key)); warn!("found value for deprecated config key `{}`", key.paint(VAL));
if let Some(ref source) = md.source { if let Some(ref source) = md.source {
launch_meta_!("in {} {}", Paint::white(source), md.name); launch_meta_!("in {} {}", source.paint(VAL), md.name);
} }
if let Some(new_key) = replacement { if let Some(new_key) = replacement {
launch_meta_!("key has been by replaced by `{}`", Paint::white(new_key)); launch_meta_!("key has been by replaced by `{}`", new_key.paint(VAL));
} else { } else {
launch_meta_!("key has no special meaning"); launch_meta_!("key has no special meaning");
} }
@ -449,10 +447,10 @@ impl Config {
// Check for now removed config values. // Check for now removed config values.
for (prefix, replacement) in Self::DEPRECATED_PROFILES { for (prefix, replacement) in Self::DEPRECATED_PROFILES {
if let Some(profile) = figment.profiles().find(|p| p.starts_with(prefix)) { if let Some(profile) = figment.profiles().find(|p| p.starts_with(prefix)) {
warn!("found set deprecated profile `{}`", Paint::white(profile)); warn!("found set deprecated profile `{}`", profile.paint(VAL));
if let Some(new_profile) = replacement { if let Some(new_profile) = replacement {
launch_meta_!("profile was replaced by `{}`", Paint::white(new_profile)); launch_meta_!("profile was replaced by `{}`", new_profile.paint(VAL));
} else { } else {
launch_meta_!("profile `{}` has no special meaning", profile); launch_meta_!("profile `{}` has no special meaning", profile);
} }
@ -460,11 +458,11 @@ impl Config {
} }
#[cfg(feature = "secrets")] { #[cfg(feature = "secrets")] {
launch_meta_!("secret key: {}", bold(&self.secret_key)); launch_meta_!("secret key: {}", self.secret_key.paint(VAL));
if !self.secret_key.is_provided() { if !self.secret_key.is_provided() {
warn!("secrets enabled without a stable `secret_key`"); warn!("secrets enabled without a stable `secret_key`");
launch_meta_!("disable `secrets` feature or configure a `secret_key`"); launch_meta_!("disable `secrets` feature or configure a `secret_key`");
launch_meta_!("this becomes an {} in non-debug profiles", Paint::red("error")); launch_meta_!("this becomes an {} in non-debug profiles", "error".red());
} }
} }
} }
@ -598,7 +596,7 @@ pub fn pretty_print_error(error: figment::Error) {
crate::log::init_default(); crate::log::init_default();
error!("Failed to extract valid configuration."); error!("Failed to extract valid configuration.");
for e in error { for e in error {
fn w<T: std::fmt::Display>(v: T) -> Paint<T> { Paint::white(v) } fn w<T>(v: T) -> yansi::Painted<T> { Paint::new(v).primary() }
match e.kind { match e.kind {
Kind::Message(msg) => error_!("{}", msg), Kind::Message(msg) => error_!("{}", msg),

View File

@ -644,8 +644,9 @@ mod with_tls_feature {
Either::Left(path) => { Either::Left(path) => {
let path = path.relative(); let path = path.relative();
let file = fs::File::open(&path).map_err(move |e| { let file = fs::File::open(&path).map_err(move |e| {
Error::new(e.kind(), format!("error reading TLS file `{}`: {}", let source = figment::Source::File(path);
Paint::white(figment::Source::File(path)), e)) let msg = format!("error reading TLS file `{}`: {}", source.primary(), e);
Error::new(e.kind(), msg)
})?; })?;
Ok(Box::new(io::BufReader::new(file))) Ok(Box::new(io::BufReader::new(file)))

View File

@ -7,6 +7,7 @@ use tokio::fs::File;
use tokio::io::{AsyncRead, AsyncWrite, AsyncReadExt, ReadBuf, Take}; use tokio::io::{AsyncRead, AsyncWrite, AsyncReadExt, ReadBuf, Take};
use futures::stream::Stream; use futures::stream::Stream;
use futures::ready; use futures::ready;
use yansi::Paint;
use crate::http::hyper; use crate::http::hyper;
use crate::ext::{PollExt, Chain}; use crate::ext::{PollExt, Chain};
@ -261,8 +262,7 @@ impl AsyncRead for DataStream<'_> {
StreamKind::Multipart(_) => "a multipart form field", StreamKind::Multipart(_) => "a multipart form field",
}; };
let msg = yansi::Paint::default(kind).bold(); warn_!("Data limit reached while reading {}.", kind.primary().bold());
warn_!("Data limit reached while reading {}.", msg);
} }
Pin::new(&mut self.chain).poll_read(cx, buf) Pin::new(&mut self.chain).poll_read(cx, buf)

View File

@ -188,7 +188,7 @@ impl Error {
error!("Rocket failed to launch due to the following {} collisions:", kind); error!("Rocket failed to launch due to the following {} collisions:", kind);
for &(ref a, ref b) in collisions { for &(ref a, ref b) in collisions {
info_!("{} {} {}", a, Paint::red("collides with").italic(), b) info_!("{} {} {}", a, "collides with".red().italic(), b)
} }
} }
@ -208,7 +208,7 @@ impl Error {
} }
ErrorKind::InsecureSecretKey(profile) => { ErrorKind::InsecureSecretKey(profile) => {
error!("secrets enabled in non-debug without `secret_key`"); error!("secrets enabled in non-debug without `secret_key`");
info_!("selected profile: {}", Paint::default(profile).bold()); info_!("selected profile: {}", profile.primary().bold());
info_!("disable `secrets` feature or configure a `secret_key`"); info_!("disable `secrets` feature or configure a `secret_key`");
"aborting due to insecure configuration" "aborting due to insecure configuration"
} }
@ -219,7 +219,7 @@ impl Error {
ErrorKind::SentinelAborts(ref failures) => { ErrorKind::SentinelAborts(ref failures) => {
error!("Rocket failed to launch due to aborting sentinels:"); error!("Rocket failed to launch due to aborting sentinels:");
for sentry in failures { for sentry in failures {
let name = Paint::default(sentry.type_name).bold(); let name = sentry.type_name.primary().bold();
let (file, line, col) = sentry.location; let (file, line, col) = sentry.location;
info_!("{} ({}:{}:{})", name, file, line, col); info_!("{} ({}:{}:{})", name, file, line, col);
} }

View File

@ -173,11 +173,11 @@ impl Fairings {
pub fn pretty_print(&self) { pub fn pretty_print(&self) {
let active_fairings = self.active().collect::<HashSet<_>>(); let active_fairings = self.active().collect::<HashSet<_>>();
if !active_fairings.is_empty() { if !active_fairings.is_empty() {
launch_meta!("{}{}:", Paint::emoji("📡 "), Paint::magenta("Fairings")); launch_meta!("{}{}:", "📡 ".emoji(), "Fairings".magenta());
for (_, fairing) in iter!(self, active_fairings.into_iter()) { for (_, fairing) in iter!(self, active_fairings.into_iter()) {
launch_meta_!("{} ({})", Paint::default(fairing.info().name).bold(), let (name, kind) = (fairing.info().name, fairing.info().kind);
Paint::blue(fairing.info().kind).bold()); launch_meta_!("{} ({})", name.primary().bold(), kind.blue().bold());
} }
} }
} }

View File

@ -147,12 +147,12 @@ impl FileServer {
if !options.contains(Options::Missing) { if !options.contains(Options::Missing) {
if !options.contains(Options::IndexFile) && !path.is_dir() { if !options.contains(Options::IndexFile) && !path.is_dir() {
let path = path.display(); let path = path.display();
error!("FileServer path '{}' is not a directory.", Paint::white(path)); error!("FileServer path '{}' is not a directory.", path.primary());
warn_!("Aborting early to prevent inevitable handler failure."); warn_!("Aborting early to prevent inevitable handler failure.");
panic!("invalid directory: refusing to continue"); panic!("invalid directory: refusing to continue");
} else if !path.exists() { } else if !path.exists() {
let path = path.display(); let path = path.display();
error!("FileServer path '{}' is not a file.", Paint::white(path)); error!("FileServer path '{}' is not a file.", path.primary());
warn_!("Aborting early to prevent inevitable handler failure."); warn_!("Aborting early to prevent inevitable handler failure.");
panic!("invalid file: refusing to continue"); panic!("invalid file: refusing to continue");
} }

View File

@ -536,7 +536,7 @@ impl<'r> FromData<'r> for Capped<TempFile<'_>> {
let has_form = |ty: &ContentType| ty.is_form_data() || ty.is_form(); let has_form = |ty: &ContentType| ty.is_form_data() || ty.is_form();
if req.content_type().map_or(false, has_form) { if req.content_type().map_or(false, has_form) {
let (tf, form) = (Paint::white("TempFile<'_>"), Paint::white("Form<TempFile<'_>>")); let (tf, form) = ("TempFile<'_>".primary(), "Form<TempFile<'_>>".primary());
warn_!("Request contains a form that will not be processed."); warn_!("Request contains a form that will not be processed.");
info_!("Bare `{}` data guard writes raw, unprocessed streams to disk.", tf); info_!("Bare `{}` data guard writes raw, unprocessed streams to disk.", tf);
info_!("Did you mean to use `{}` instead?", form); info_!("Did you mean to use `{}` instead?", form);

View File

@ -4,9 +4,8 @@ use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use is_terminal::IsTerminal;
use serde::{de, Serialize, Serializer, Deserialize, Deserializer}; use serde::{de, Serialize, Serializer, Deserialize, Deserializer};
use yansi::Paint; use yansi::{Paint, Painted, Condition};
/// Reexport the `log` crate as `private`. /// Reexport the `log` crate as `private`.
pub use log as private; pub use log as private;
@ -81,8 +80,8 @@ pub enum LogLevel {
Off, Off,
} }
pub trait PaintExt { pub trait PaintExt: Sized {
fn emoji(item: &str) -> Paint<&str>; fn emoji(self) -> Painted<Self>;
} }
// Whether a record is a special `launch_{meta,info}!` record. // Whether a record is a special `launch_{meta,info}!` record.
@ -116,7 +115,7 @@ impl log::Log for RocketLogger {
// In Rocket, we abuse targets with suffix "_" to indicate indentation. // In Rocket, we abuse targets with suffix "_" to indicate indentation.
let indented = record.target().ends_with('_'); let indented = record.target().ends_with('_');
if indented { if indented {
write_out!(" {} ", Paint::default(">>").bold()); write_out!(" {} ", ">>".bold());
} }
// Downgrade a physical launch `warn` to logical `info`. // Downgrade a physical launch `warn` to logical `info`.
@ -126,27 +125,23 @@ impl log::Log for RocketLogger {
match level { match level {
log::Level::Error if !indented => { log::Level::Error if !indented => {
write_out!("{} {}\n", write_out!("{} {}\n", "Error:".red().bold(), record.args().red().wrap());
Paint::red("Error:").bold(),
Paint::red(record.args()).wrap());
} }
log::Level::Warn if !indented => { log::Level::Warn if !indented => {
write_out!("{} {}\n", write_out!("{} {}\n", "Warning:".yellow().bold(), record.args().yellow().wrap());
Paint::yellow("Warning:").bold(),
Paint::yellow(record.args()).wrap());
} }
log::Level::Info => write_out!("{}\n", Paint::blue(record.args()).wrap()), log::Level::Info => write_out!("{}\n", record.args().blue().wrap()),
log::Level::Trace => write_out!("{}\n", Paint::magenta(record.args()).wrap()), log::Level::Trace => write_out!("{}\n", record.args().magenta().wrap()),
log::Level::Warn => write_out!("{}\n", Paint::yellow(record.args()).wrap()), log::Level::Warn => write_out!("{}\n", record.args().yellow().wrap()),
log::Level::Error => write_out!("{}\n", Paint::red(record.args()).wrap()), log::Level::Error => write_out!("{}\n", &record.args().red().wrap()),
log::Level::Debug => { log::Level::Debug => {
write_out!("\n{} ", Paint::blue("-->").bold()); write_out!("\n{} ", "-->".blue().bold());
if let Some(file) = record.file() { if let Some(file) = record.file() {
write_out!("{}", Paint::blue(file)); write_out!("{}", file.blue());
} }
if let Some(line) = record.line() { if let Some(line) = record.line() {
write_out!(":{}\n", Paint::blue(line)); write_out!(":{}\n", line.blue());
} }
write_out!("\t{}\n", record.args()); write_out!("\t{}\n", record.args());
@ -171,18 +166,12 @@ pub(crate) fn init(config: &crate::Config) {
ROCKET_LOGGER_SET.store(true, Ordering::Release); ROCKET_LOGGER_SET.store(true, Ordering::Release);
} }
// Always disable colors if requested or if they won't work on Windows. // Always disable colors if requested or if the stdout/err aren't TTYs.
if !config.cli_colors || !Paint::enable_windows_ascii() { let should_color = config.cli_colors && Condition::stdouterr_are_tty();
Paint::disable(); yansi::whenever(Condition::cached(should_color));
}
// Set Rocket-logger specific settings only if Rocket's logger is set. // Set Rocket-logger specific settings only if Rocket's logger is set.
if ROCKET_LOGGER_SET.load(Ordering::Acquire) { if ROCKET_LOGGER_SET.load(Ordering::Acquire) {
// Rocket logs to stdout, so disable coloring if it's not a TTY.
if !std::io::stdout().is_terminal() {
Paint::disable();
}
log::set_max_level(config.log_level.into()); log::set_max_level(config.log_level.into());
} }
} }
@ -247,10 +236,10 @@ impl<'de> Deserialize<'de> for LogLevel {
} }
} }
impl PaintExt for Paint<&str> { impl PaintExt for &str {
/// Paint::masked(), but hidden on Windows due to broken output. See #1122. /// Paint::masked(), but hidden on Windows due to broken output. See #1122.
fn emoji(_item: &str) -> Paint<&str> { fn emoji(self) -> Painted<Self> {
#[cfg(windows)] { Paint::masked("") } #[cfg(windows)] { Paint::new("").mask() }
#[cfg(not(windows))] { Paint::masked(_item) } #[cfg(not(windows))] { Paint::new(self).mask() }
} }
} }

View File

@ -765,6 +765,6 @@ impl<S, E, F> fmt::Debug for Outcome<S, E, F> {
impl<S, E, F> fmt::Display for Outcome<S, E, F> { impl<S, E, F> fmt::Display for Outcome<S, E, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (color, string) = self.formatting(); let (color, string) = self.formatting();
write!(f, "{}", Paint::default(string).fg(color)) write!(f, "{}", string.paint(color))
} }
} }

View File

@ -1110,15 +1110,12 @@ impl fmt::Debug for Request<'_> {
impl fmt::Display for Request<'_> { impl fmt::Display for Request<'_> {
/// Pretty prints a Request. Primarily used by Rocket's logging. /// Pretty prints a Request. Primarily used by Rocket's logging.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", Paint::green(self.method()), Paint::blue(&self.uri))?; write!(f, "{} {}", self.method().green(), self.uri.blue())?;
// Print the requests media type when the route specifies a format. // Print the requests media type when the route specifies a format.
if let Some(media_type) = self.format() { if let Some(mime) = self.format() {
if !media_type.is_any() { if !mime.is_any() {
write!(f, " {}{}{}", write!(f, " {}/{}", mime.top().yellow().linger(), mime.sub().clear())?;
Paint::yellow(media_type.top()),
Paint::yellow("/"),
Paint::yellow(media_type.sub()))?;
} }
} }

View File

@ -78,8 +78,8 @@ impl<E> From<E> for Debug<E> {
impl<'r, E: std::fmt::Debug> Responder<'r, 'static> for Debug<E> { impl<'r, E: std::fmt::Debug> Responder<'r, 'static> for Debug<E> {
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
warn_!("Debug: {:?}", Paint::default(self.0)); warn_!("Debug: {:?}", self.0.primary());
warn_!("Debug always responds with {}.", Status::InternalServerError); warn_!("Debug always responds with {}.", Status::InternalServerError.primary());
Err(Status::InternalServerError) Err(Status::InternalServerError)
} }
} }
@ -87,7 +87,7 @@ impl<'r, E: std::fmt::Debug> Responder<'r, 'static> for Debug<E> {
/// Prints a warning with the error and forwards to the `500` error catcher. /// Prints a warning with the error and forwards to the `500` error catcher.
impl<'r> Responder<'r, 'static> for std::io::Error { impl<'r> Responder<'r, 'static> for std::io::Error {
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
warn_!("I/O Error: {:?}", yansi::Paint::default(self)); warn_!("I/O Error: {:?}", self.primary());
Err(Status::InternalServerError) Err(Status::InternalServerError)
} }
} }

View File

@ -255,7 +255,7 @@ impl Rocket<Build> {
Err(e) => { Err(e) => {
error!("invalid {} base: {}", kind, Paint::white(&base)); error!("invalid {} base: {}", kind, Paint::white(&base));
error_!("{}", e); error_!("{}", e);
info_!("{} {}", Paint::white("in"), std::panic::Location::caller()); info_!("{} {}", "in".primary(), std::panic::Location::caller());
panic!("aborting due to {} base error", kind); panic!("aborting due to {} base error", kind);
} }
}; };
@ -600,7 +600,7 @@ fn log_items<T, I, B, O>(e: &str, t: &str, items: I, base: B, origin: O)
{ {
let mut items: Vec<_> = items.collect(); let mut items: Vec<_> = items.collect();
if !items.is_empty() { if !items.is_empty() {
launch_meta!("{}{}:", Paint::emoji(e), Paint::magenta(t)); launch_meta!("{}{}:", e.emoji(), t.magenta());
} }
items.sort_by_key(|i| origin(i).path().as_str().chars().count()); items.sort_by_key(|i| origin(i).path().as_str().chars().count());
@ -678,9 +678,7 @@ impl Rocket<Ignite> {
async fn _local_launch(self) -> Rocket<Orbit> { async fn _local_launch(self) -> Rocket<Orbit> {
let rocket = self.into_orbit(); let rocket = self.into_orbit();
rocket.fairings.handle_liftoff(&rocket).await; rocket.fairings.handle_liftoff(&rocket).await;
launch_info!("{}{}", Paint::emoji("🚀 "), launch_info!("{}{}", "🚀 ".emoji(), "Rocket has launched locally".primary().bold());
Paint::default("Rocket has launched into local orbit").bold());
rocket rocket
} }
@ -693,9 +691,9 @@ impl Rocket<Ignite> {
let socket_addr = SocketAddr::new(rkt.config.address, rkt.config.port); let socket_addr = SocketAddr::new(rkt.config.address, rkt.config.port);
let addr = format!("{}://{}", proto, socket_addr); let addr = format!("{}://{}", proto, socket_addr);
launch_info!("{}{} {}", launch_info!("{}{} {}",
Paint::emoji("🚀 "), "🚀 ".emoji(),
Paint::default("Rocket has launched from").bold(), "Rocket has launched from".bold().primary().linger(),
Paint::default(addr).bold().underline()); addr.underline());
})) }))
.await .await
.map(|rocket| rocket.into_ignite()) .map(|rocket| rocket.into_ignite())

View File

@ -346,18 +346,18 @@ impl Route {
impl fmt::Display for Route { impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref n) = self.name { if let Some(ref n) = self.name {
write!(f, "{}{}{} ", Paint::cyan("("), Paint::white(n), Paint::cyan(")"))?; write!(f, "{}{}{} ", "(".cyan(), n.primary(), ")".cyan())?;
} }
write!(f, "{} ", Paint::green(&self.method))?; write!(f, "{} ", self.method.green())?;
self.uri.color_fmt(f)?; self.uri.color_fmt(f)?;
if self.rank > 1 { if self.rank > 1 {
write!(f, " [{}]", Paint::default(&self.rank).bold())?; write!(f, " [{}]", self.rank.primary().bold())?;
} }
if let Some(ref format) = self.format { if let Some(ref format) = self.format {
write!(f, " {}", Paint::yellow(format))?; write!(f, " {}", format.yellow())?;
} }
Ok(()) Ok(())

View File

@ -247,10 +247,9 @@ impl<'a> RouteUri<'a> {
.map(|raw| raw.as_str()) .map(|raw| raw.as_str())
.unwrap_or(unmounted.as_str()); .unwrap_or(unmounted.as_str());
write!(f, "{}", Paint::blue(self.base()).underline())?; write!(f, "{}{}", self.base().blue().underline(), unmounted_part.blue())?;
write!(f, "{}", Paint::blue(unmounted_part))?;
if let Some(q) = self.unmounted().query() { if let Some(q) = self.unmounted().query() {
write!(f, "{}{}", Paint::yellow("?"), Paint::yellow(q))?; write!(f, "{}{}", "?".yellow(), q.yellow())?;
} }
Ok(()) Ok(())

View File

@ -31,7 +31,7 @@ async fn handle<Fut, T, F>(name: Option<&str>, run: F) -> Option<T>
macro_rules! panic_info { macro_rules! panic_info {
($name:expr, $e:expr) => {{ ($name:expr, $e:expr) => {{
match $name { match $name {
Some(name) => error_!("Handler {} panicked.", Paint::white(name)), Some(name) => error_!("Handler {} panicked.", name.primary()),
None => error_!("A handler panicked.") None => error_!("A handler panicked.")
}; };
@ -129,7 +129,7 @@ impl Rocket<Orbit> {
}; };
match self._send_response(response, tx).await { match self._send_response(response, tx).await {
Ok(()) => info_!("{}", Paint::green("Response succeeded.")), Ok(()) => info_!("{}", "Response succeeded.".green()),
Err(e) if remote_hungup(&e) => warn_!("Remote left: {}.", e), Err(e) if remote_hungup(&e) => warn_!("Remote left: {}.", e),
Err(e) => warn_!("Failed to write response: {}.", e), Err(e) => warn_!("Failed to write response: {}.", e),
} }
@ -284,7 +284,7 @@ impl Rocket<Orbit> {
let mut response = match self.route(request, data).await { let mut response = match self.route(request, data).await {
Outcome::Success(response) => response, Outcome::Success(response) => response,
Outcome::Forward((data, _)) if request.method() == Method::Head => { Outcome::Forward((data, _)) if request.method() == Method::Head => {
info_!("Autohandling {} request.", Paint::default("HEAD").bold()); info_!("Autohandling {} request.", "HEAD".primary().bold());
// Dispatch the request again with Method `GET`. // Dispatch the request again with Method `GET`.
request._set_method(Method::Get); request._set_method(Method::Get);
@ -334,7 +334,7 @@ impl Rocket<Orbit> {
// Check if the request processing completed (Some) or if the // Check if the request processing completed (Some) or if the
// request needs to be forwarded. If it does, continue the loop // request needs to be forwarded. If it does, continue the loop
// (None) to try again. // (None) to try again.
info_!("{} {}", Paint::default("Outcome:").bold(), outcome); info_!("{} {}", "Outcome:".primary().bold(), outcome);
match outcome { match outcome {
o@Outcome::Success(_) | o@Outcome::Failure(_) => return o, o@Outcome::Success(_) | o@Outcome::Failure(_) => return o,
Outcome::Forward(forwarded) => (data, status) = forwarded, Outcome::Forward(forwarded) => (data, status) = forwarded,
@ -372,7 +372,7 @@ impl Rocket<Orbit> {
.map(|result| result.map_err(Some)) .map(|result| result.map_err(Some))
.unwrap_or_else(|| Err(None)) .unwrap_or_else(|| Err(None))
} else { } else {
let code = Paint::blue(status.code).bold(); let code = status.code.blue().bold();
warn_!("No {} catcher registered. Using Rocket default.", code); warn_!("No {} catcher registered. Using Rocket default.", code);
Ok(crate::catcher::default_handler(status, req)) Ok(crate::catcher::default_handler(status, req))
} }

View File

@ -207,10 +207,10 @@ impl Fairing for Shield {
} }
if !self.headers().is_empty() { if !self.headers().is_empty() {
info!("{}{}:", Paint::emoji("🛡️ "), Paint::magenta("Shield")); info!("{}{}:", "🛡️ ".emoji(), "Shield".magenta());
for header in self.headers() { for header in self.headers() {
info_!("{}: {}", header.name(), Paint::default(header.value())); info_!("{}: {}", header.name(), header.value().primary());
} }
if force_hsts { if force_hsts {

View File

@ -3,6 +3,7 @@ use std::ops::Deref;
use std::any::type_name; use std::any::type_name;
use ref_cast::RefCast; use ref_cast::RefCast;
use yansi::Paint;
use crate::{Phase, Rocket, Ignite, Sentinel}; use crate::{Phase, Rocket, Ignite, Sentinel};
use crate::request::{self, FromRequest, Request}; use crate::request::{self, FromRequest, Request};
@ -210,8 +211,8 @@ impl<'r, T: Send + Sync + 'static> FromRequest<'r> for &'r State<T> {
impl<T: Send + Sync + 'static> Sentinel for &State<T> { impl<T: Send + Sync + 'static> Sentinel for &State<T> {
fn abort(rocket: &Rocket<Ignite>) -> bool { fn abort(rocket: &Rocket<Ignite>) -> bool {
if rocket.state::<T>().is_none() { if rocket.state::<T>().is_none() {
let type_name = yansi::Paint::default(type_name::<T>()).bold(); let type_name = type_name::<T>();
error!("launching with unmanaged `{}` state.", type_name); error!("launching with unmanaged `{}` state.", type_name.primary().bold());
info_!("Using `State` requires managing it with `.manage()`."); info_!("Using `State` requires managing it with `.manage()`.");
return true; return true;
} }