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, 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 match overwrite_link_fmt.or(Some(DEBUG_IDE)).unwrap_or_default() {
107 LinkDebugIde::NoLink => format!(
108 "`{}:{}:{}`",
109 self.filename,
112 self.line_number,
113 self.column_number
114 ),
115 LinkDebugIde::Browser => format!(
116 "\x1b]8;;file://{absolute_path}:{line}:{column}\x1b\\{relative_path}:{line}:{column}\x1b]8;;\x1b\\",
117 line = self.line_number,
120 column = self.column_number,
121 ),
122 LinkDebugIde::Vscode => format!(
123 "\x1b]8;;vscode://file/{absolute_path}:{line}:{column}\x1b\\{relative_path}:{line}:{column}\x1b]8;;\x1b\\",
124 line = self.line_number,
127 column = self.column_number,
128 ),
129 }
130 }
131}
132
133#[cfg(debug_assertions)]
135static DEBUG_IDE: LinkDebugIde = LinkDebugIde::Vscode;
136#[cfg(not(debug_assertions))]
138static DEBUG_IDE: LinkDebugIde = LinkDebugIde::NoLink;
139
140impl Display for SourceLocation {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 write!(f, "{}", self.display_location(None))
143 }
144}