Improve backtraces when hovering widgets with modifiers pressed (#4696)
A useful debug-feature in egui is pressing down all modifiers keys and hovering any widget to see its backtrace (only in `dev` builds). Unfortunately this is incompatible with `panic="abort"`, something I just now discovered. So I removed `panic="abort"` from `Cargo.toml` for `dev` builds. If the backtrace returns empty-handed, I also suggests this as a fix to the user. Finally, I cleaned up the backtraces a bit, making them slightly shorter and more readable.
This commit is contained in:
parent
b1dc059ef3
commit
db8db50bf3
|
|
@ -43,7 +43,10 @@ panic = "abort" # This leads to better optimizations and smaller binaries (and i
|
||||||
# split-debuginfo = "unpacked" # faster debug builds on mac
|
# split-debuginfo = "unpacked" # faster debug builds on mac
|
||||||
# opt-level = 1 # Make debug builds run faster
|
# opt-level = 1 # Make debug builds run faster
|
||||||
|
|
||||||
panic = "abort" # This leads to better optimizations and smaller binaries (and is the default in Wasm anyways).
|
# panic = "abort" leads to better optimizations and smaller binaries (and is the default in Wasm anyways),
|
||||||
|
# but it also means backtraces don't work with the `backtrace` library (https://github.com/rust-lang/backtrace-rs/issues/397).
|
||||||
|
# egui has a feature where if you hold down all modifiers keys on your keyboard and hover any UI widget,
|
||||||
|
# you will see the backtrace to that widget, and we don't want to break that feature in dev builds.
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
# Optimize all dependencies even in debug builds (does not affect workspace packages):
|
# Optimize all dependencies even in debug builds (does not affect workspace packages):
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ struct Frame {
|
||||||
///
|
///
|
||||||
/// In particular: slips everything before `egui::Context::run`,
|
/// In particular: slips everything before `egui::Context::run`,
|
||||||
/// and skipping all frames in the `egui::` namespace.
|
/// and skipping all frames in the `egui::` namespace.
|
||||||
|
#[inline(never)]
|
||||||
pub fn capture() -> String {
|
pub fn capture() -> String {
|
||||||
let mut frames = vec![];
|
let mut frames = vec![];
|
||||||
let mut depth = 0;
|
let mut depth = 0;
|
||||||
|
|
@ -28,7 +29,7 @@ pub fn capture() -> String {
|
||||||
|
|
||||||
let name = symbol
|
let name = symbol
|
||||||
.name()
|
.name()
|
||||||
.map(|name| name.to_string())
|
.map(|name| clean_symbol_name(name.to_string()))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
frames.push(Frame {
|
frames.push(Frame {
|
||||||
|
|
@ -44,12 +45,13 @@ pub fn capture() -> String {
|
||||||
});
|
});
|
||||||
|
|
||||||
if frames.is_empty() {
|
if frames.is_empty() {
|
||||||
return Default::default();
|
return
|
||||||
|
"Failed to capture a backtrace. A common cause of this is compiling with panic=\"abort\" (https://github.com/rust-lang/backtrace-rs/issues/397)".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inclusive:
|
// Inclusive:
|
||||||
let mut min_depth = 0;
|
let mut min_depth = 0;
|
||||||
let mut max_depth = frames.len() - 1;
|
let mut max_depth = usize::MAX;
|
||||||
|
|
||||||
for frame in &frames {
|
for frame in &frames {
|
||||||
if frame.name.starts_with("egui::callstack::capture") {
|
if frame.name.starts_with("egui::callstack::capture") {
|
||||||
|
|
@ -60,14 +62,23 @@ pub fn capture() -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this the name of some sort of useful entry point?
|
||||||
|
fn is_start_name(name: &str) -> bool {
|
||||||
|
name == "main"
|
||||||
|
|| name == "_main"
|
||||||
|
|| name.starts_with("eframe::run_native")
|
||||||
|
|| name.starts_with("egui::context::Context::run")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut has_kept_any_start_names = false;
|
||||||
|
|
||||||
|
frames.reverse(); // main on top, i.e. chronological order. Same as Python.
|
||||||
|
|
||||||
// Remove frames that are uninteresting:
|
// Remove frames that are uninteresting:
|
||||||
frames.retain(|frame| {
|
frames.retain(|frame| {
|
||||||
// Keep some special frames to give the user a sense of chronology:
|
// Keep the first "start" frame we can detect (e.g. `main`) to give the user a sense of chronology:
|
||||||
if frame.name == "main"
|
if is_start_name(&frame.name) && !has_kept_any_start_names {
|
||||||
|| frame.name == "_main"
|
has_kept_any_start_names = true;
|
||||||
|| frame.name.starts_with("egui::context::Context::run")
|
|
||||||
|| frame.name.starts_with("eframe::run_native")
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,8 +107,6 @@ pub fn capture() -> String {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
frames.reverse(); // main on top, i.e. chronological order. Same as Python.
|
|
||||||
|
|
||||||
let mut deepest_depth = 0;
|
let mut deepest_depth = 0;
|
||||||
let mut widest_file_line = 0;
|
let mut widest_file_line = 0;
|
||||||
for frame in &frames {
|
for frame in &frames {
|
||||||
|
|
@ -135,6 +144,28 @@ pub fn capture() -> String {
|
||||||
formatted
|
formatted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clean_symbol_name(mut s: String) -> String {
|
||||||
|
// We get a hex suffix (at least on macOS) which is quite unhelpful,
|
||||||
|
// e.g. `my_crate::my_function::h3bedd97b1e03baa5`.
|
||||||
|
// Let's strip that.
|
||||||
|
if let Some(h) = s.rfind("::h") {
|
||||||
|
let hex = &s[h + 3..];
|
||||||
|
if hex.len() == 16 && hex.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||||
|
s.truncate(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clean_symbol_name() {
|
||||||
|
assert_eq!(
|
||||||
|
clean_symbol_name("my_crate::my_function::h3bedd97b1e03baa5".to_owned()),
|
||||||
|
"my_crate::my_function"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Shorten a path to a Rust source file from a callstack.
|
/// Shorten a path to a Rust source file from a callstack.
|
||||||
///
|
///
|
||||||
/// Example input:
|
/// Example input:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue