Handle newly added files
This commit is contained in:
parent
45d356aa92
commit
80441feb78
@ -1,7 +1,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::*;
|
use std::fs::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::{channel, Sender};
|
||||||
use std::sync::{Arc, RwLock, RwLockWriteGuard};
|
use std::sync::{Arc, RwLock, RwLockWriteGuard};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
@ -18,7 +18,7 @@ enum Partial {
|
|||||||
File(Css),
|
File(Css),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
|
||||||
enum FileState {
|
enum FileState {
|
||||||
Clean,
|
Clean,
|
||||||
Dirty,
|
Dirty,
|
||||||
@ -42,10 +42,36 @@ impl CssFile {
|
|||||||
state: FileState::Clean,
|
state: FileState::Clean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drop_dead(&mut self) {
|
||||||
|
let mut old = vec![];
|
||||||
|
std::mem::swap(&mut self.lines, &mut old);
|
||||||
|
|
||||||
|
for child in old {
|
||||||
|
match child {
|
||||||
|
Partial::String(_) => {
|
||||||
|
self.lines.push(child);
|
||||||
|
}
|
||||||
|
Partial::File(file) => {
|
||||||
|
let state = file.read().map(|f| f.state).unwrap();
|
||||||
|
|
||||||
|
if state != FileState::Dead {
|
||||||
|
if let Ok(mut css) = file.write() {
|
||||||
|
css.drop_dead();
|
||||||
|
}
|
||||||
|
self.lines.push(Partial::File(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for CssFile {
|
impl std::fmt::Display for CssFile {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.state == FileState::Dead {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
f.write_str(format!("\n/* -- {} --- */\n\n", self.path).as_str())?;
|
f.write_str(format!("\n/* -- {} --- */\n\n", self.path).as_str())?;
|
||||||
for line in self.lines.iter() {
|
for line in self.lines.iter() {
|
||||||
match line {
|
match line {
|
||||||
@ -74,6 +100,7 @@ struct Application {
|
|||||||
files_map: HashMap<String, HashSet<String>>,
|
files_map: HashMap<String, HashSet<String>>,
|
||||||
fm: HashMap<String, Css>,
|
fm: HashMap<String, Css>,
|
||||||
root_file: Option<Css>,
|
root_file: Option<Css>,
|
||||||
|
sender: Option<Sender<DebouncedEvent>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
@ -119,11 +146,19 @@ impl Application {
|
|||||||
.clone()
|
.clone()
|
||||||
.parent()
|
.parent()
|
||||||
.ok_or_else(|| format!("Not a valid path {:?}", input))?;
|
.ok_or_else(|| format!("Not a valid path {:?}", input))?;
|
||||||
let file = self
|
|
||||||
.fm
|
let file = if self.fm.contains_key(&file_path) {
|
||||||
.entry(file_path.clone())
|
self.fm.get(&file_path).unwrap().clone()
|
||||||
.or_insert_with(|| Arc::new(RwLock::new(CssFile::new(file_path.clone()))))
|
} else {
|
||||||
.clone();
|
let css = Arc::new(RwLock::new(CssFile::new(file_path.clone())));
|
||||||
|
self.fm.insert(file_path.clone(), css.clone());
|
||||||
|
if let Some(ref tx) = self.sender {
|
||||||
|
let path = Path::new(&file_path);
|
||||||
|
tx.send(DebouncedEvent::Create(path.to_path_buf()))
|
||||||
|
.map_err(|e| format!("{}", e))?;
|
||||||
|
}
|
||||||
|
css
|
||||||
|
};
|
||||||
|
|
||||||
if let Ok(mut css) = file.write() {
|
if let Ok(mut css) = file.write() {
|
||||||
css.last_changed = Self::read_timestamp(input)?;
|
css.last_changed = Self::read_timestamp(input)?;
|
||||||
@ -183,6 +218,28 @@ impl Application {
|
|||||||
.and_then(|css| css.write().or(Err(false)))
|
.and_then(|css| css.write().or(Err(false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh(&mut self) {
|
||||||
|
if let Ok(mut root) = self
|
||||||
|
.root_file
|
||||||
|
.as_mut()
|
||||||
|
.ok_or_else(|| false)
|
||||||
|
.and_then(|f| f.write().map_err(|_| false))
|
||||||
|
{
|
||||||
|
root.drop_dead();
|
||||||
|
}
|
||||||
|
let mut old = HashMap::new();
|
||||||
|
std::mem::swap(&mut old, &mut self.fm);
|
||||||
|
for (key, file) in old.into_iter() {
|
||||||
|
if file
|
||||||
|
.read()
|
||||||
|
.map(|f| f.state != FileState::Dead)
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
self.fm.insert(key, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print(&self) {
|
fn print(&self) {
|
||||||
let css = match self.root_file.as_ref().unwrap().read() {
|
let css = match self.root_file.as_ref().unwrap().read() {
|
||||||
Ok(css) => css,
|
Ok(css) => css,
|
||||||
@ -197,6 +254,10 @@ impl Application {
|
|||||||
_ => println!("{}", css),
|
_ => println!("{}", css),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pipe(&mut self, tx: Sender<DebouncedEvent>) {
|
||||||
|
self.sender = Some(tx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), String> {
|
||||||
@ -224,6 +285,7 @@ fn main() -> Result<(), String> {
|
|||||||
files_map: Default::default(),
|
files_map: Default::default(),
|
||||||
fm: Default::default(),
|
fm: Default::default(),
|
||||||
root_file: None,
|
root_file: None,
|
||||||
|
sender: None,
|
||||||
};
|
};
|
||||||
let root_path = app.input.to_string();
|
let root_path = app.input.to_string();
|
||||||
let root = std::path::Path::new(&root_path);
|
let root = std::path::Path::new(&root_path);
|
||||||
@ -240,18 +302,13 @@ fn main() -> Result<(), String> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
app.pipe(tx.clone());
|
||||||
|
let mut watcher = watcher(tx.clone(), Duration::from_secs(1)).unwrap();
|
||||||
|
|
||||||
app.parse()?;
|
app.parse()?;
|
||||||
app.print();
|
app.print();
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
|
||||||
|
|
||||||
for file in app.fm.keys() {
|
|
||||||
watcher
|
|
||||||
.watch(file.to_string(), RecursiveMode::NonRecursive)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match rx.recv() {
|
match rx.recv() {
|
||||||
Ok(DebouncedEvent::NoticeWrite(path)) => {
|
Ok(DebouncedEvent::NoticeWrite(path)) => {
|
||||||
@ -264,9 +321,16 @@ fn main() -> Result<(), String> {
|
|||||||
Ok(DebouncedEvent::NoticeRemove(path)) => {
|
Ok(DebouncedEvent::NoticeRemove(path)) => {
|
||||||
app.mark_dead(path.as_path());
|
app.mark_dead(path.as_path());
|
||||||
watcher.unwatch(path).unwrap();
|
watcher.unwatch(path).unwrap();
|
||||||
|
app.refresh();
|
||||||
|
app.print();
|
||||||
}
|
}
|
||||||
Ok(event) => println!("{:?}", event),
|
Ok(DebouncedEvent::Create(path)) => {
|
||||||
Err(e) => println!("watch error: {:?}", e),
|
if let Err(e) = watcher.watch(path, RecursiveMode::NonRecursive) {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_event) => (),
|
||||||
|
Err(e) => eprintln!("watch error: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user