diff --git a/Cargo.toml b/Cargo.toml index bc3ead4..e7f6f07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ fancy-no-backtrace = [ "dep:supports-unicode", ] fancy = ["fancy-no-backtrace", "dep:backtrace", "dep:backtrace-ext"] -syntect-highlighter = ["fancy-no-backtrace", "dep:syntect"] +syntect-highlighter = ["fancy-no-backtrace", "dep:syntect", "std"] [workspace] members = ["miette-derive"] diff --git a/README.md b/README.md index 8ecc16d..084ce0d 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ diagnostic error code: ruget::api::bad_json ### Features -- Generic [`Diagnostic`] protocol, compatible (and dependent on) - [`std::error::Error`]. +- Generic [`Diagnostic`] protocol, compatible with `std::error::Error`. + Works without the standard library: Just turn off the default `std` feature and you can use `miette` in places like embedded systems or web browsers that don't have the full standard library. You still need `alloc` for memory management. - Unique error codes on every [`Diagnostic`]. - Custom links to get more details on error codes. - Super handy derive macro for defining diagnostic metadata. @@ -93,6 +93,19 @@ If you want to use the fancy printer in all these screenshots: $ cargo add miette --features fancy ``` +For computers without the standard library (like microcontrollers or web browsers): + +```sh +$ cargo add miette --no-default-features --features derive +``` + +Available features you can turn on or off: +- `std` (on by default): Use the standard library +- `derive`: Lets you automatically create error types +- `fancy`: Shows pretty error messages with colors +- `fancy-no-syscall`: Pretty errors without using system calls +- `fancy-no-backtrace`: Pretty errors without showing the call stack + ### Example ```rust diff --git a/build.rs b/build.rs index 20e6ce0..296a4eb 100644 --- a/build.rs +++ b/build.rs @@ -5,12 +5,8 @@ fn main() { println!("cargo:rustc-cfg=nightly") } - // Configure track_caller based on Rust version - if let Ok(version) = rustc_version::version() { - if version >= rustc_version::Version::new(1, 46, 0) { - println!("cargo:rustc-cfg=track_caller"); - } - } + // track_caller is stable since Rust 1.46 (2020), so no version check needed + println!("cargo:rustc-cfg=track_caller"); // Add check-cfg for conditional configurations println!("cargo:rustc-check-cfg=cfg(doc_cfg)"); diff --git a/miette-derive/src/code.rs b/miette-derive/src/code.rs index 8ebe920..83cb053 100644 --- a/miette-derive/src/code.rs +++ b/miette-derive/src/code.rs @@ -56,13 +56,13 @@ impl Code { let code = &code.as_ref()?.0; Some(match fields { syn::Fields::Named(_) => { - quote! { Self::#ident { .. } => Option::Some(alloc::boxed::Box::new(#code)), } + quote! { Self::#ident { .. } => core::option::Option::Some(alloc::boxed::Box::new(#code)), } } syn::Fields::Unnamed(_) => { - quote! { Self::#ident(..) => Option::Some(alloc::boxed::Box::new(#code)), } + quote! { Self::#ident(..) => core::option::Option::Some(alloc::boxed::Box::new(#code)), } } syn::Fields::Unit => { - quote! { Self::#ident => Option::Some(alloc::boxed::Box::new(#code)), } + quote! { Self::#ident => core::option::Option::Some(alloc::boxed::Box::new(#code)), } } }) }, @@ -72,8 +72,8 @@ impl Code { pub(crate) fn gen_struct(&self) -> Option { let code = &self.0; Some(quote! { - fn code(&self) -> Option> { - Some(alloc::boxed::Box::new(#code)) + fn code(&self) -> core::option::Option> { + core::option::Option::Some(alloc::boxed::Box::new(#code)) } }) } diff --git a/miette-derive/src/diagnostic_source.rs b/miette-derive/src/diagnostic_source.rs index 7864e4a..35b5e35 100644 --- a/miette-derive/src/diagnostic_source.rs +++ b/miette-derive/src/diagnostic_source.rs @@ -59,7 +59,7 @@ impl DiagnosticSource { }; quote! { Self::#ident #display_pat => { - Some(alloc::borrow::Borrow::borrow(#rel)) + core::option::Option::Some(alloc::borrow::Borrow::borrow(#rel)) } } }) @@ -70,8 +70,8 @@ impl DiagnosticSource { pub(crate) fn gen_struct(&self) -> Option { let rel = &self.0; Some(quote! { - fn diagnostic_source<'a>(&'a self) -> Option<&'a dyn miette::Diagnostic> { - Some(alloc::borrow::Borrow::borrow(&self.#rel)) + fn diagnostic_source<'a>(&'a self) -> core::option::Option<&'a dyn miette::Diagnostic> { + core::option::Option::Some(alloc::borrow::Borrow::borrow(&self.#rel)) } }) } diff --git a/src/error.rs b/src/error.rs index 9e2faad..f54f4d8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -93,6 +93,9 @@ impl Diagnostic for MietteError { pub(crate) mod tests { #[cfg(not(feature = "std"))] use crate::StdError as Error; + #[cfg(not(feature = "std"))] + use alloc::string::ToString; + #[cfg(feature = "std")] use std::string::ToString; use super::*; @@ -101,6 +104,7 @@ pub(crate) mod tests { #[cfg(feature = "std")] pub(crate) struct TestError(pub(crate) io::Error); #[cfg(not(feature = "std"))] + #[derive(Debug)] pub(crate) struct TestError(pub(crate) &'static str); impl Display for TestError { diff --git a/src/eyreish/error.rs b/src/eyreish/error.rs index 0add102..2dc0a3c 100644 --- a/src/eyreish/error.rs +++ b/src/eyreish/error.rs @@ -817,14 +817,6 @@ impl AsRef for Report { } } -#[cfg(feature = "std")] -impl std::borrow::Borrow for Report { - fn borrow(&self) -> &(dyn Diagnostic + 'static) { - self.as_ref() - } -} - -#[cfg(not(feature = "std"))] impl core::borrow::Borrow for Report { fn borrow(&self) -> &(dyn Diagnostic + 'static) { self.as_ref() diff --git a/src/eyreish/into_diagnostic.rs b/src/eyreish/into_diagnostic.rs index 2ed2aae..83262a5 100644 --- a/src/eyreish/into_diagnostic.rs +++ b/src/eyreish/into_diagnostic.rs @@ -60,13 +60,12 @@ impl IntoDiagnostic for Result #[cfg(test)] mod tests { + use super::IntoDiagnostic; #[cfg(feature = "std")] use std::io::{self}; #[cfg(feature = "std")] use std::string::ToString; - use super::*; - #[cfg(feature = "std")] use crate::error::tests::TestError; diff --git a/src/handler.rs b/src/handler.rs index 6dc2df1..32a2e5e 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -357,7 +357,7 @@ impl MietteHandlerOpts { // In no-std environment, assume graphics are available true } - #[cfg(not(feature = "fancy-no-syscall"))] + #[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))] { // In std environment, check NO_GRAPHICS env var if let Ok(env) = std::env::var("NO_GRAPHICS") { @@ -366,6 +366,11 @@ impl MietteHandlerOpts { true } } + #[cfg(all(not(feature = "fancy-no-syscall"), not(feature = "std")))] + { + // In no-std environment without fancy-no-syscall, default to true + true + } } } @@ -487,8 +492,10 @@ mod syscall { cfg_if! { if #[cfg(any(feature = "fancy-no-syscall", miri))] { None - } else { + } else if #[cfg(feature = "fancy-no-backtrace")] { terminal_size::terminal_size().map(|size| size.0 .0 as usize) + } else { + None } } } @@ -498,8 +505,10 @@ mod syscall { cfg_if! { if #[cfg(feature = "fancy-no-syscall")] { false - } else { + } else if #[cfg(feature = "fancy-no-backtrace")] { supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr) + } else { + false } } } @@ -507,13 +516,18 @@ mod syscall { #[inline] pub(super) fn supports_color() -> bool { cfg_if! { - if #[cfg(feature = "fancy-no-backtrace")] { + if #[cfg(all(feature = "fancy", not(feature = "fancy-no-syscall")))] { + // Standard fancy mode with full std support supports_color::on(supports_color::Stream::Stderr).is_some() - } else if #[cfg(feature = "fancy-no-syscall")] { - // In no-std environment without color support, default to no color support + } else if #[cfg(all(feature = "fancy", feature = "fancy-no-backtrace"))] { + // Fancy mode without backtrace but with color support + supports_color::on(supports_color::Stream::Stderr).is_some() + } else if #[cfg(not(feature = "std"))] { + // No-std environment - no color support by default false } else { - true // Fallback to assuming color support + // All other cases - no color support + false } } } @@ -537,8 +551,10 @@ mod syscall { cfg_if! { if #[cfg(feature = "fancy-no-syscall")] { false - } else { + } else if #[cfg(feature = "fancy-no-backtrace")] { supports_unicode::on(supports_unicode::Stream::Stderr) + } else { + false } } } diff --git a/src/handlers/theme.rs b/src/handlers/theme.rs index 168ff89..f51b42f 100644 --- a/src/handlers/theme.rs +++ b/src/handlers/theme.rs @@ -76,7 +76,7 @@ impl Default for GraphicalTheme { // In no-std environments, default to no-color mode Self::unicode_nocolor() } - #[cfg(not(feature = "fancy-no-syscall"))] + #[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))] { match std::env::var("NO_COLOR") { _ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => { @@ -86,6 +86,11 @@ impl Default for GraphicalTheme { _ => Self::unicode(), } } + #[cfg(all(not(feature = "fancy-no-syscall"), not(feature = "std")))] + { + // In no-std environment, default to unicode theme + Self::unicode() + } } } diff --git a/src/highlighters/syntect.rs b/src/highlighters/syntect.rs index ca848f6..d5df64e 100644 --- a/src/highlighters/syntect.rs +++ b/src/highlighters/syntect.rs @@ -1,3 +1,4 @@ +use core::str; use std::path::Path; extern crate alloc; diff --git a/src/lib.rs b/src/lib.rs index 24cefff..79ed0fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,8 +60,8 @@ //! //! ## Features //! -//! - Generic [`Diagnostic`] protocol, compatible (and dependent on) -//! [`std::error::Error`]. +//! - Generic [`Diagnostic`] protocol, compatible with `std::error::Error`. +//! Works without the standard library: Just turn off the default `std` feature and you can use `miette` in places like embedded systems or web browsers that don't have the full standard library. You still need `alloc` for memory management. //! - Unique error codes on every [`Diagnostic`]. //! - Custom links to get more details on error codes. //! - Super handy derive macro for defining diagnostic metadata. @@ -95,6 +95,19 @@ //! $ cargo add miette --features fancy //! ``` //! +//! For computers without the standard library (like microcontrollers or web browsers): +//! +//! ```sh +//! $ cargo add miette --no-default-features --features derive +//! ``` +//! +//! Available features you can turn on or off: +//! - `std` (on by default): Use the standard library +//! - `derive`: Lets you automatically create error types +//! - `fancy`: Shows pretty error messages with colors +//! - `fancy-no-syscall`: Pretty errors without using system calls +//! - `fancy-no-backtrace`: Pretty errors without showing the call stack +//! //! ## Example //! //! ```rust @@ -829,10 +842,6 @@ //! under the Apache License. Some code is taken from //! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed. -// For doctests that use Diagnostic derive macro -#[cfg(test)] -extern crate alloc; - #[cfg(feature = "std")] extern crate std; diff --git a/src/panic.rs b/src/panic.rs index ef6f427..eb57601 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "std")] use std::boxed::Box; +#[cfg(feature = "std")] use std::{ eprintln, error::Error, @@ -7,11 +9,14 @@ use std::{ string::{String, ToString}, }; +#[cfg(feature = "std")] use backtrace::Backtrace; +#[cfg(feature = "std")] use crate::{Context, Diagnostic, Result}; -/// Tells miette to render panics using its rendering engine. +/// Makes miette show pretty error messages when your program crashes. +#[cfg(feature = "std")] pub fn set_panic_hook() { std::panic::set_hook(Box::new(move |info| { let mut message = "Something went wrong".to_string(); @@ -33,9 +38,20 @@ pub fn set_panic_hook() { })); } +/// Makes miette show pretty error messages when your program crashes. +/// +/// On computers without the standard library, this function does nothing +/// because crash hooks need the standard library to work. +#[cfg(not(feature = "std"))] +pub fn set_panic_hook() { + // Does nothing on computers without the standard library +} + #[derive(Debug)] +#[cfg(feature = "std")] struct Panic(String); +#[cfg(feature = "std")] impl Display for Panic { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let msg = &self.0; @@ -44,8 +60,10 @@ impl Display for Panic { } } +#[cfg(feature = "std")] impl Error for Panic {} +#[cfg(feature = "std")] impl Diagnostic for Panic { fn help<'a>(&'a self) -> Option> { Some(Box::new( @@ -54,6 +72,7 @@ impl Diagnostic for Panic { } } +#[cfg(feature = "std")] impl Panic { fn backtrace() -> String { use std::fmt::Write; @@ -110,6 +129,7 @@ impl Panic { } #[cfg(test)] +#[cfg(feature = "std")] mod tests { use std::{borrow::ToOwned, error::Error};