#![forbid(unsafe_code)]
#![deny(
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications,
bad_style,
dead_code,
unused,
while_true
)]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
#[macro_use]
extern crate log;
use chrono::Local;
use colored::Colorize;
use fern::Dispatch;
use kqueue2::{Ident::*, Watcher};
use lw::config::Config;
use lw::consts::DEFAULT_THEME;
use lw::types::FileAndPosition;
use lw::utils::{process_file_event, walkdir_recursive, watch_the_watcher};
use std::{env, fs::OpenOptions, path::Path, process::exit, thread, time::Duration};
fn main() {
let wrote_default_config = Config::existing_config_path().is_none();
let config = Config::load();
let log_level = config.get_log_level();
let output = config.output.clone().unwrap_or_default();
let paths_to_watch: Vec<String> = env::args()
.skip(1) .collect();
let mut watched_file_states = FileAndPosition::new();
let mut kqueue_watcher = Watcher::new().expect("Could not create kqueue watcher!");
let mut last_file = String::new();
Dispatch::new()
.format(|out, message, _record| {
out.finish(format_args!(
"{}: {}",
Local::now().to_rfc3339().black(),
message
))
})
.level(log_level)
.chain(
OpenOptions::new()
.create(true)
.append(true)
.open(output.clone())
.unwrap_or_else(|_| {
panic!("{}: Couldn't open: {}!", "FATAL ERROR".red(), output.cyan())
}),
)
.apply()
.expect("Couldn't initialize Fern logger!");
if wrote_default_config {
info!(
"No configuration file found — wrote defaults to: {}",
Config::default_config_path().cyan()
);
}
lw::highlight::init(config.theme.as_deref().unwrap_or(DEFAULT_THEME));
debug!("Watching paths: {}", paths_to_watch.join(", "));
if paths_to_watch.is_empty() {
error!("FATAL ERROR: {}", "No paths specified as arguments! You have to specify at least a single directory/file to watch!".red());
exit(1)
}
paths_to_watch.into_iter().for_each(|a_path| {
walkdir_recursive(
&mut kqueue_watcher,
&mut watched_file_states,
&mut last_file,
Path::new(&a_path),
&config,
);
});
loop {
watch_the_watcher(&mut kqueue_watcher);
while let Some(an_event) = kqueue_watcher.iter().next() {
debug!("Watched files: {}", watched_file_states.len());
match an_event.ident {
Filename(_file_descriptor, abs_file_name) => {
process_file_event(
&abs_file_name,
&mut kqueue_watcher,
&mut watched_file_states,
&mut last_file,
&config,
);
watch_the_watcher(&mut kqueue_watcher);
}
event => warn!("Unknown event: {}", format!("{event:?}").cyan()),
}
}
thread::sleep(Duration::from_millis(100));
}
}