charon_error/utils/
source_location.rs1use std::{fmt::Display, panic::Location};
4use tracing::Metadata;
5
6use crate::ResultExt;
7
8#[derive(Debug, Clone, Default, Copy)]
13pub enum LinkDebugIde {
14 #[default]
16 NoLink,
17 Browser,
19 Vscode,
21}
22
23#[derive(Debug, Clone)]
28pub struct SourceLocation {
29 pub crate_name: &'static str,
31 pub crate_version: &'static str,
33 pub filename: String,
35 pub line_number: u32,
37 pub column_number: u32,
39}
40
41impl SourceLocation {
42 fn check_if_abs_path(path: &str) -> bool {
43 path.starts_with('/')
44 }
45
46 #[must_use]
48 #[track_caller]
49 pub fn from_caller_location() -> Self {
50 let caller = Location::caller();
51 Self {
52 crate_name: env!("CARGO_PKG_NAME"),
53 crate_version: env!("CARGO_PKG_VERSION"),
54 filename: caller.file().to_owned(),
55 line_number: caller.line(),
56 column_number: caller.column(),
57 }
58 }
59
60 #[must_use]
62 pub fn from_panic_location(location: &Location) -> Self {
63 Self {
64 crate_name: env!("CARGO_PKG_NAME"),
65 crate_version: env!("CARGO_PKG_VERSION"),
66 filename: location.file().to_owned(),
67 line_number: location.line(),
68 column_number: location.column(),
69 }
70 }
71
72 #[must_use]
74 pub fn from_metadata(metadata: &Metadata) -> Self {
75 Self {
76 crate_name: env!("CARGO_PKG_NAME"),
77 crate_version: env!("CARGO_PKG_VERSION"),
78 filename: metadata.file().unwrap_or("Unknown").to_owned(),
79 line_number: metadata.line().unwrap_or(0),
80 column_number: 0,
81 }
82 }
83
84 #[must_use]
86 pub fn display_location(&self, mut overwrite_link_fmt: Option<LinkDebugIde>) -> String {
87 let current_dir = std::env::current_dir().unwrap_error().display().to_string();
88
89 let relative_path = if Self::check_if_abs_path(&self.filename) {
90 let current_dir = format!("{current_dir}/");
92 if self.filename.starts_with(¤t_dir) {
93 self.filename.split_at(current_dir.len()).1.to_owned()
94 } else {
95 self.filename.clone()
96 }
97 } else {
98 self.filename.clone()
99 };
100
101 let absolute_path = if Self::check_if_abs_path(&self.filename) {
102 self.filename.clone()
103 } else {
104 format!("{}/{}", current_dir, self.filename)
105 };
106 if std::env::var("NO_COLOR").is_ok() {
108 overwrite_link_fmt = Some(LinkDebugIde::NoLink);
109 }
110
111 match overwrite_link_fmt.or(Some(DEBUG_IDE)).unwrap_or_default() {
112 LinkDebugIde::NoLink => format!(
113 "{}:{}:{}",
114 self.filename,
117 self.line_number,
118 self.column_number
119 ),
120 LinkDebugIde::Browser => format!(
121 "\x1b]8;;file://{absolute_path}:{line}:{column}\x1b\\{relative_path}:{line}:{column}\x1b]8;;\x1b\\",
122 line = self.line_number,
125 column = self.column_number,
126 ),
127 LinkDebugIde::Vscode => format!(
128 "\x1b]8;;vscode://file/{absolute_path}:{line}:{column}\x1b\\{relative_path}:{line}:{column}\x1b]8;;\x1b\\",
129 line = self.line_number,
132 column = self.column_number,
133 ),
134 }
135 }
136}
137
138#[cfg(debug_assertions)]
140static DEBUG_IDE: LinkDebugIde = LinkDebugIde::Vscode;
141#[cfg(not(debug_assertions))]
143static DEBUG_IDE: LinkDebugIde = LinkDebugIde::NoLink;
144
145impl Display for SourceLocation {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 write!(f, "{}", self.display_location(None))
148 }
149}