rapx/utils/
log.rs

1use chrono::Local;
2use fern::colors::{Color, ColoredLevelConfig};
3use fern::{self, Dispatch};
4use log::LevelFilter;
5use rustc_span::source_map::get_source_map;
6use rustc_span::{FileNameDisplayPreference, Pos, Span};
7use std::ops::Range;
8
9fn log_level() -> LevelFilter {
10    if let Ok(s) = std::env::var("RAP_LOG") {
11        match s.parse() {
12            Ok(level) => return level,
13            Err(err) => eprintln!("RAP_LOG is invalid: {err}"),
14        }
15    }
16    LevelFilter::Info
17}
18
19/// Detect `RAP_LOG` environment variable first; if it's not set,
20/// default to INFO level.
21pub fn init_log() -> Result<(), fern::InitError> {
22    let dispatch = Dispatch::new().level(log_level());
23
24    let color_line = ColoredLevelConfig::new()
25        .error(Color::Red)
26        .warn(Color::Yellow)
27        .info(Color::White)
28        .debug(Color::Blue)
29        .trace(Color::Cyan);
30
31    let color_level = color_line.info(Color::Green);
32    let stderr_dispatch = Dispatch::new()
33        .format(move |callback, args, record| {
34            let now = Local::now();
35            callback.finish(format_args!(
36                "{}{}|RAP|{}{}|: {}\x1B[0m",
37                format_args!(
38                    "\x1B[{}m",
39                    color_line.get_color(&record.level()).to_fg_str()
40                ),
41                now.format("%H:%M:%S"),
42                color_level.color(record.level()),
43                format_args!(
44                    "\x1B[{}m",
45                    color_line.get_color(&record.level()).to_fg_str()
46                ),
47                args
48            ))
49        })
50        .chain(std::io::stderr());
51
52    /* Note that we cannot dispatch to stdout due to some bugs */
53    dispatch.chain(stderr_dispatch).apply()?;
54    Ok(())
55}
56
57#[macro_export]
58macro_rules! rap_trace {
59    ($($arg:tt)+) => (
60        ::log::trace!(target: "RAP", $($arg)+)
61    );
62}
63
64#[macro_export]
65macro_rules! rap_debug {
66    ($($arg:tt)+) => (
67        ::log::debug!(target: "RAP", $($arg)+)
68    );
69}
70
71#[macro_export]
72macro_rules! rap_info {
73    ($($arg:tt)+) => (
74        ::log::info!(target: "RAP", $($arg)+)
75    );
76}
77
78#[macro_export]
79macro_rules! rap_warn {
80    ($($arg:tt)+) => (
81        ::log::warn!(target: "RAP", $($arg)+)
82    );
83}
84
85#[macro_export]
86macro_rules! rap_error {
87    ($($arg:tt)+) => (
88        ::log::error!(target: "RAP", $($arg)+)
89    );
90}
91
92pub fn rap_error_and_exit(msg: impl AsRef<str>) -> ! {
93    rap_error!("{}", msg.as_ref());
94    std::process::exit(1)
95}
96
97#[inline]
98pub fn span_to_source_code(span: Span) -> String {
99    get_source_map().unwrap().span_to_snippet(span).unwrap()
100}
101
102#[inline]
103pub fn span_to_first_line(span: Span) -> Span {
104    // extend the span to an entrie line or extract the first line if it has multiple lines
105    get_source_map()
106        .unwrap()
107        .span_extend_to_line(span.shrink_to_lo())
108}
109
110#[inline]
111pub fn span_to_trimmed_span(span: Span) -> Span {
112    // trim out the first few whitespace
113    span.trim_start(
114        get_source_map()
115            .unwrap()
116            .span_take_while(span, |c| c.is_whitespace()),
117    )
118    .unwrap()
119}
120
121#[inline]
122pub fn span_to_filename(span: Span) -> String {
123    get_source_map()
124        .unwrap()
125        .span_to_filename(span)
126        .display(FileNameDisplayPreference::Local)
127        .to_string()
128}
129
130#[inline]
131pub fn span_to_line_number(span: Span) -> usize {
132    get_source_map().unwrap().lookup_char_pos(span.lo()).line
133}
134
135#[inline]
136// this function computes the relative pos range of two spans which could be generated from two dirrerent files or not intersect with each other
137// warning: we just return 0..0 to drop off the unintersected pairs
138pub fn relative_pos_range(span: Span, sub_span: Span) -> Range<usize> {
139    if sub_span.lo() < span.lo() || sub_span.hi() > span.hi() {
140        return 0..0;
141    }
142    let offset = span.lo();
143    let lo = (sub_span.lo() - offset).to_usize();
144    let hi = (sub_span.hi() - offset).to_usize();
145    lo..hi
146}
147
148pub fn are_spans_in_same_file(span1: Span, span2: Span) -> bool {
149    let file1 = get_source_map().unwrap().lookup_source_file(span1.lo());
150    let file2 = get_source_map().unwrap().lookup_source_file(span2.lo());
151    file1.name == file2.name
152}