1pub mod cmd;
2pub mod config;
3pub mod renderer;
4pub mod utils;
5
6use std::io::{self, Stdout};
7use std::sync::LazyLock;
8use std::{env, panic};
9
10use color_eyre::config::HookBuilder;
11use color_eyre::eyre::{self, Result};
12use ratatui::Terminal;
13use ratatui::backend::CrosstermBackend;
14use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture};
15use ratatui::crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
16use ratatui::crossterm::{self};
17use unic_langid::LanguageIdentifier;
18
19fluent_templates::static_loader! {
20 static LOCALES = {
21 locales: "./locales",
22 fallback_language: "en-US",
23 customise: |bundle| bundle.set_use_isolating(false),
26 };
27}
28
29pub static LANG_ID: LazyLock<LanguageIdentifier> = LazyLock::new(|| {
30 let mut locale = sys_locale::get_locale().unwrap_or_else(|| {
31 eprintln!("Failed to get active locale for the system, use `en-US`");
32 String::from("en-US")
33 });
34
35 if locale == "zh-CN" {
36 locale = "zh-Hans".to_string();
37 } else if locale == "zh-HK" || locale == "zh-TW" {
38 locale = "zh-Hant".to_string();
39 } else if locale == "C" {
40 locale = "en-US".to_string();
41 }
42
43 match locale.parse::<LanguageIdentifier>() {
44 Ok(lang_id) => lang_id,
45 Err(error) => {
46 eprintln!("Failed to parse LanguageIdentifier: {error}, use `en-US`");
47 "en-US".parse::<LanguageIdentifier>().unwrap()
48 }
49 }
50});
51
52pub fn init_error_hooks(restore: bool) -> Result<()> {
53 if env::var("RUST_SPANTRACE").is_err() {
54 unsafe {
55 env::set_var("RUST_SPANTRACE", "0");
56 }
57 }
58
59 let (panic_hook, eyre_hook) = HookBuilder::default().into_hooks();
60
61 let panic_hook = panic_hook.into_panic_hook();
62 panic::set_hook(Box::new(move |panic_info| {
63 if restore {
64 let _ = restore_terminal();
65 }
66 panic_hook(panic_info);
67 }));
68
69 let eyre_hook = eyre_hook.into_eyre_hook();
70 eyre::set_hook(Box::new(move |e| {
71 if restore {
72 let _ = restore_terminal();
73 }
74 eyre_hook(e)
75 }))?;
76
77 Ok(())
78}
79
80pub(crate) type Tui = Terminal<CrosstermBackend<Stdout>>;
81
82pub(crate) fn init_terminal() -> Result<Tui> {
83 crossterm::execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?;
84 terminal::enable_raw_mode()?;
85 Ok(Terminal::new(CrosstermBackend::new(io::stdout()))?)
86}
87
88pub(crate) fn restore_terminal() -> Result<()> {
89 crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
90 terminal::disable_raw_mode()?;
91 Ok(())
92}