Skip to content

Commit

Permalink
Various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nilehmann committed Jul 8, 2024
1 parent 613b2d1 commit fcc8ccf
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 140 deletions.
61 changes: 43 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,53 @@ Arguments:
[CMD]...

Options:
--style <STYLE> Set the backtrace style to `short` (RUST_BACKTRACE=1) or `full`
(RUST_BACKTRACE=full) [default: short] [possible values: short, full]
--lib-backtrace <LIB_BACKTRACE> Enable or disable `Backtrace::capture`. If this flag is set to `no`,
backtracetk sets RUST_LIB_BACKTRACE=0, disabling
`Backtrace::capture`. If the flag is set to `yes`, no changes are
made, and the default behavior of capturing backtraces remains
enabled [default: no] [possible values: yes, no]
--clicolor-force <CLICOLOR_FORCE> If this flag is `yes`, set CLICOLOR_FORCE=1. If the flag is `no`, no
changes are made [default: yes] [possible values: yes, no]
--hide-output By default, backtracetk prints each captured line as it reads it,
providing immediate feedback. If this flag is set, this output is
suppressed, and nothing will be printed until the program exits
-h, --help Print help
--print-config Print the current detected configuration
--print-default-config Print the default configuration used when no configuration files are detected
-h, --help Print help

```

### Configuration

Backtracetk will search for a configuration file named `backtrack.toml` or `.backtrack.toml` in the parent directories starting from the directory where the command is executed. Currently, the only supported configuration option is hide, which accepts an array of tables. Each table can take one of two forms:
Backtracetk can be configured using a TOML file named `backtracetk.toml` or `.backtracetk.toml`.
It searches for a *global* configuration file in your home directory and a *local* configuration file in the parent directories starting from the current working directory. The local configuration will override the global configuration where they overlap.

Below is a sample configuration:

```toml
# Backtracetk Configuration File

# `style` sets the backtrace detail level.
# Options:
# - "short" (default): Sets `RUST_BACKTRACE=1`
# - "full": Sets `RUST_BACKTRACE=full`
style = "short"

# `echo` controls whether backtracetk echoes captured lines.
# - true (default): Captured lines are printed as they are read
# - false: Suppresses output until the program exits
echo = true

* A table with the key `pattern` and a value containing a regex. Any frame matching this pattern will be hidden from the output.
* A table with the keys `start` and `end`, both containing regex values. Every frame between a frame matching the `start` regex and a frame matching the `end` regex will be hidden. The `end` pattern is optional; if omitted, every frame after matching `start` will be hidden.
# `env` allows specifying additional environment variables for the child process.
[env]
CLICOLOR_FORCE = "1" # e.g., force ANSI colors
RUST_LIB_BACKTRACE = "0" # e.g., disable lib backtrace

For an example:
# `links` configures the emission of hyperlinks for file paths in the backtrace output.
[hyperlinks]
enabled = true # Enable or disable hyperlinking.
url = "vscode://file${FILE_PATH}:{$LINE}:{$COLUMN}" # Template for generating file links.

![Screenshot2](./screenshot2.png)
# `hide` sections define rules to exclude specific frames from the backtrace output.
# Frames can be hidden based on regex patterns or ranges between start and end patterns.

# Hide frames matching a specific regex pattern.
[[hide]]
pattern = "panic_macro::fn2" # Regex pattern to match frames for exclusion.

# Hide frames within a range defined by start and end regex patterns.
[[hide]]
begin = "core::panicking" # Start pattern.
end = "rust_begin_unwind" # End pattern (optional). If omitted, hides all subsequent frames.

```
34 changes: 31 additions & 3 deletions backtracetk.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
# Backtracetk Configuration File

# `style` sets the backtrace detail level.
# Options:
# - "short" (default): Sets `RUST_BACKTRACE=1`
# - "full": Sets `RUST_BACKTRACE=full`
style = "short"

# `echo` controls whether backtracetk echoes captured lines.
# - true (default): Captured lines are printed as they are read
# - false: Suppresses output until the program exits
echo = true

# `env` allows specifying additional environment variables for the child process.
[env]
CLICOLOR_FORCE = "1" # e.g., force ANSI colors
RUST_LIB_BACKTRACE = "0" # e.g., disable lib backtrace

# `links` configures the emission of hyperlinks for file paths in the backtrace output.
[hyperlinks]
enabled = true # Enable or disable hyperlinking.
url = "vscode://file${FILE_PATH}:{$LINE}:{$COLUMN}" # Template for generating file links.

# `hide` sections define rules to exclude specific frames from the backtrace output.
# Frames can be hidden based on regex patterns or ranges between start and end patterns.

# Hide frames matching a specific regex pattern.
[[hide]]
pattern = "panic_macro::fn2"
pattern = "panic_macro::fn2" # Regex pattern to match frames for exclusion.

# Hide frames within a range defined by start and end regex patterns.
[[hide]]
begin = "core::panicking"
end = "rust_begin_unwind"
begin = "core::panicking" # Start pattern.
end = "rust_begin_unwind" # End pattern (optional). If omitted, hides all subsequent frames.
53 changes: 13 additions & 40 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ fn complete_derive(s: Structure) -> TokenStream {
s.gen_impl(quote! {
gen impl crate::partial::Complete for @Self {
type Partial = Option<Self>;

fn into_partial(self) -> Option<Self> {
Some(self)
}
}
})
}
Expand All @@ -65,13 +69,20 @@ fn partialize_derive_inner(s: Structure) -> syn::Result<TokenStream> {

let ident = &s.ast().ident;
let partial_ident = Ident::new(&format!("Partial{ident}"), Span::call_site());
let partial_body: TokenStream = iter_fields(data)
let partial_fields: TokenStream = iter_fields(data)
.map(|(f, ty)| quote! { #f: <#ty as crate::partial::Complete>::Partial, })
.collect();
let into_partial_fields: TokenStream = iter_fields(data)
.map(|(f, ty)| quote! { #f: <#ty as crate::partial::Complete>::into_partial(self.#f), })
.collect();

let complete_impl = s.gen_impl(quote! {
gen impl crate::partial::Complete for @Self {
type Partial = #partial_ident;

fn into_partial(self) -> #partial_ident {
#partial_ident { #into_partial_fields }
}
}
});

Expand All @@ -80,7 +91,7 @@ fn partialize_derive_inner(s: Structure) -> syn::Result<TokenStream> {
#[complete(#ident)]
#[serde(default)]
pub struct #partial_ident {
#partial_body
#partial_fields
}

#complete_impl
Expand All @@ -106,41 +117,3 @@ fn check_is_struct<'a>(trait_: &str, s: &'a Structure) -> syn::Result<&'a syn::D
)),
}
}

#[cfg(test)]
mod tests {
use super::merge_derive;

#[test]
fn test00() {
synstructure::test_derive! {
merge_derive {
#[complete(A)]
struct A {
a: i32,
b: i32,
}
}
expands to {
const _: () = {
impl crate::merge::Merge for A {
fn merge_with(mut self, other: Self) -> Self {
Self {
a: other.a.merge_with(self.a),
b: other.b.merge_with(self.b),
}
}

fn to_complete(mut self, other: Self) -> Self {
Self {
a: self.a.to_complete(),
b: self.b.to_complete(),
}
}
}
};
}
no_build
}
}
}
Binary file modified screenshot1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screenshot2.png
Binary file not shown.
82 changes: 42 additions & 40 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::fmt;
use std::{
collections::HashMap,
fs,
io::{self, Read},
io::Read,
path::{Path, PathBuf},
};

Expand All @@ -12,37 +12,21 @@ use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};

use crate::partial::Partial;
use crate::partial::{Complete, Partial};

#[derive(Serialize, Partialize)]
#[derive(Serialize, Partialize, Debug)]
pub struct Config {
pub style: BacktraceStyle,
pub hide: Vec<Hide>,
pub echo: Echo,
pub hyperlinks: HyperLinks,
pub env: HashMap<String, String>,
pub clicolor_force: ColorChoice,
pub hide_output: bool,
pub links: Links,
pub hide: Vec<Hide>,
}

impl Config {
pub fn read() -> anyhow::Result<Config> {
PartialConfig::read().map(PartialConfig::into_complete)
}

pub fn should_set_clicolor_force(&self) -> bool {
match self.clicolor_force {
ColorChoice::Auto => {
match anstream::AutoStream::choice(&io::stderr()) {
anstream::ColorChoice::Never => false,
anstream::ColorChoice::AlwaysAnsi | anstream::ColorChoice::Always => true,
// this should never happen
anstream::ColorChoice::Auto => false,
}
}
ColorChoice::Always => true,
ColorChoice::Never => false,
}
}
}

impl fmt::Display for Config {
Expand All @@ -55,25 +39,24 @@ impl Default for Config {
fn default() -> Self {
Self {
style: Default::default(),
hide: vec![Hide::Span {
hide: vec![Hide::Range {
begin: Regex::new("core::panicking::panic_explicit").unwrap(),
end: None,
}],
env: Default::default(),
clicolor_force: Default::default(),
hide_output: false,
links: Default::default(),
echo: Default::default(),
hyperlinks: Default::default(),
}
}
}

#[derive(Serialize, Partialize)]
pub struct Links {
#[derive(Serialize, Partialize, Debug)]
pub struct HyperLinks {
pub enabled: bool,
pub url: String,
}

impl Links {
impl HyperLinks {
pub fn render(&self, file: &str, line: usize, col: usize) -> String {
self.url
.replace("${LINE}", &format!("{line}"))
Expand All @@ -82,7 +65,7 @@ impl Links {
}
}

impl Default for Links {
impl Default for HyperLinks {
fn default() -> Self {
Self {
enabled: false,
Expand All @@ -91,16 +74,35 @@ impl Default for Links {
}
}

#[derive(Clone, Copy, Serialize, clap::ValueEnum, Deserialize, Debug, Default, Complete)]
#[serde(rename_all = "lowercase")]
pub enum ColorChoice {
#[derive(Clone, Copy, Serialize, Deserialize, Complete, Default, Debug)]
#[serde(from = "bool")]
#[serde(into = "bool")]
pub enum Echo {
#[default]
Auto,
Always,
Never,
True,
False,
}

impl From<bool> for Echo {
fn from(b: bool) -> Self {
if b {
Echo::True
} else {
Echo::False
}
}
}

impl Into<bool> for Echo {
fn into(self) -> bool {
match self {
Echo::True => true,
Echo::False => false,
}
}
}

#[derive(Clone, Copy, Serialize, Deserialize, clap::ValueEnum, Debug, Default, Complete)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, Default, Complete)]
#[serde(rename_all = "lowercase")]
pub enum BacktraceStyle {
#[default]
Expand All @@ -125,7 +127,7 @@ pub enum Hide {
#[serde_as(as = "DisplayFromStr")]
pattern: Regex,
},
Span {
Range {
#[serde_as(as = "DisplayFromStr")]
begin: Regex,
#[serde_as(as = "Option<DisplayFromStr>")]
Expand Down Expand Up @@ -178,7 +180,7 @@ impl<'de> Deserialize<'de> for Hide {
} else if let Some(begin) = entries.remove(BEGIN) {
let begin = re(&begin)?;
let end = entries.remove(END).as_deref().map(re).transpose()?;
Ok(Hide::Span { begin, end })
Ok(Hide::Range { begin, end })
} else {
Err(Error::custom(format!(
"missing field `{PATTERN}` or `{BEGIN}`"
Expand All @@ -195,7 +197,7 @@ impl PartialConfig {
let config = PartialConfig::find_home_file()
.map(PartialConfig::parse_file)
.transpose()?
.unwrap_or_default();
.unwrap_or_else(|| Config::default().into_partial());
let Some(local_path) = PartialConfig::find_local_file() else {
return Ok(config);
};
Expand Down
Loading

0 comments on commit fcc8ccf

Please sign in to comment.