Krolyxon
Commit dbc22bf

Branches

Tags

Refs →

remagesrcmain.rs

151 lines · 4.5 KB · Rust

1//! remage: a keyboard-centric image viewer.
2
3mod action;
4mod anim;
5mod app;
6mod cache;
7mod cli;
8mod config;
9mod decode;
10mod exec;
11mod input;
12mod ipc;
13mod render;
14mod scan;
15mod state;
16mod thumbs;
17mod ui;
18mod worker;
19
20use std::path::Path;
21use std::time::Instant;
22
23use clap::Parser;
24use winit::event_loop::EventLoop;
25
26use app::{App, Options, Overrides, UserEvent};
27use state::queue::Queue;
28use state::{AppState, MsgKind, Settings};
29
30fn main() -> anyhow::Result<()> {
31 let started = Instant::now();
32 env_logger::init();
33 let cli = cli::Cli::parse();
34 if cli.dump_config {
35 print!("{}", config::dump());
36 return Ok(());
37 }
38 if cli.check_config {
39 check_config(cli.config.as_deref());
40 }
41 log::info!("remage {}", env!("CARGO_PKG_VERSION"));
42
43 let (loaded, config_error) = match config::load(cli.config.as_deref()) {
44 Ok(l) => (l, None),
45 Err(e) => {
46 log::error!("{e}");
47 let mut d = config::defaults();
48 d.watch = e.watch;
49 (d, Some(e.message))
50 }
51 };
52 for w in &loaded.warnings {
53 log::warn!("{w}");
54 }
55 log::debug!("config loaded after {:.1?}", started.elapsed());
56 let cfg = &loaded.config;
57
58 let scan = scan::scan(
59 &cli.paths,
60 &scan::ScanOptions {
61 recursive: cli.recursive || cfg.general.recursive,
62 siblings: !cli.no_siblings && cfg.general.open_siblings,
63 sort: cli.sort.unwrap_or(cfg.general.sort),
64 reverse: cli.reverse || cfg.general.reverse,
65 },
66 );
67 log::debug!(
68 "scanned {} files ({} to sniff) in {:.1?}",
69 scan.files.len(),
70 scan.unknown.len(),
71 started.elapsed()
72 );
73
74 let overrides = Overrides {
75 fit: cli.fit,
76 zoom: cli.zoom.map(|z| z / 100.0),
77 bar: cli.no_bar.then_some(false),
78 };
79 let mut settings = Settings::from_config(cfg);
80 overrides.apply(&mut settings);
81 let start_index = cli.start.unwrap_or(1).saturating_sub(1);
82 let queue = Queue::new(scan.files, scan.start.as_deref(), start_index);
83 let bar = overrides.bar.unwrap_or(cfg.ui.statusbar);
84 let mut state = AppState::new(queue, settings, bar, Instant::now());
85 if cli.grid || cfg.general.start_mode == config::StartMode::Grid {
86 state.set_mode(state::Mode::Grid, Instant::now());
87 }
88 state.theme = loaded.theme.clone();
89 state.nearest = cfg.image.filter.nearest();
90 state.alpha_bg = cfg.image.alpha_background;
91 if let Some(err) = scan.errors.first() {
92 state.notify(format!("error: {err}"), MsgKind::Error, Instant::now());
93 }
94
95 let event_loop = EventLoop::<UserEvent>::with_user_event().build()?;
96 let proxy = event_loop.create_proxy();
97 if !scan.unknown.is_empty() {
98 let proxy = proxy.clone();
99 let unknown = scan.unknown;
100 std::thread::spawn(move || {
101 let found: Vec<_> = unknown.into_iter().filter(|p| decode::sniff(p)).collect();
102 if !found.is_empty() {
103 let _ = proxy.send_event(UserEvent::Found(found));
104 }
105 });
106 }
107 let watch = {
108 let proxy = proxy.clone();
109 config::watch::spawn(cli.config.clone(), loaded.watch.clone(), move |r| {
110 let _ = proxy.send_event(UserEvent::Config(Box::new(r)));
111 })
112 };
113
114 let opts = Options {
115 fullscreen: cli.fullscreen || cfg.window.fullscreen,
116 geometry: cli.geometry,
117 class: cli.class.unwrap_or_else(|| cfg.window.class.clone()),
118 overrides,
119 private: cli.private,
120 };
121 let mut app = App::new(opts, state, proxy, loaded, watch);
122 if let Some(e) = config_error {
123 app.config_failed(&e);
124 }
125 event_loop.run_app(&mut app)?;
126 match app.error.take() {
127 Some(e) => Err(e),
128 None => Ok(()),
129 }
130}
131
132/// `--check-config`: report and exit, non-zero on errors.
133fn check_config(path: Option<&Path>) -> ! {
134 match config::load(path) {
135 Ok(l) => {
136 for w in &l.warnings {
137 eprintln!("warning: {w}");
138 }
139 match path.map(Path::to_path_buf).or_else(config::default_path) {
140 Some(p) if p.is_file() => println!("{}: ok", p.display()),
141 Some(p) => println!("{} not found: using the defaults", p.display()),
142 None => println!("no config directory: using the defaults"),
143 }
144 std::process::exit(0)
145 }
146 Err(e) => {
147 eprintln!("{e}");
148 std::process::exit(1)
149 }
150 }
151}