From b06f109d31d0cdb8c282c1c6030d4e222f9953cb Mon Sep 17 00:00:00 2001 From: NobodyForNothing <82763757+NobodyForNothing@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:22:17 +0200 Subject: [PATCH] feat: finer snippet parsing --- rust/snippets/src/snippets/creator.rs | 2 +- rust/snippets/src/snippets/lang.rs | 9 +++ rust/snippets/src/snippets/mod.rs | 32 +++++----- rust/snippets/src/snippets/snip.rs | 89 +++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 rust/snippets/src/snippets/lang.rs create mode 100644 rust/snippets/src/snippets/snip.rs diff --git a/rust/snippets/src/snippets/creator.rs b/rust/snippets/src/snippets/creator.rs index 5fef423..18a24d3 100644 --- a/rust/snippets/src/snippets/creator.rs +++ b/rust/snippets/src/snippets/creator.rs @@ -10,7 +10,7 @@ impl SnipCreator { } pub fn add(&self, name: String) -> bool { - fs::write(self.path.join(name), "todo"); + fs::write(self.path.join(name), "todo").unwrap(); true } } \ No newline at end of file diff --git a/rust/snippets/src/snippets/lang.rs b/rust/snippets/src/snippets/lang.rs new file mode 100644 index 0000000..b99faa8 --- /dev/null +++ b/rust/snippets/src/snippets/lang.rs @@ -0,0 +1,9 @@ +pub enum Lang { + Md, + /*Txt, + Rust, + Dart, + C, + Java, + Python,*/ +} \ No newline at end of file diff --git a/rust/snippets/src/snippets/mod.rs b/rust/snippets/src/snippets/mod.rs index 4d762b5..7dae4c9 100644 --- a/rust/snippets/src/snippets/mod.rs +++ b/rust/snippets/src/snippets/mod.rs @@ -1,12 +1,15 @@ use std::fs; -use colored::Colorize; +use colored::{Colorize, CustomColor}; use creator::SnipCreator; use log::{debug, error, info}; +use snip::{Snip, SnipBuilder}; use crate::input::config::Config; mod creator; +mod lang; +mod snip; pub struct SnipetsFolderBuilder<'a> { config: &'a Config, @@ -31,26 +34,21 @@ impl<'a> ValidatedSnipptsFolder<'a> { pub fn index(self) -> Option> { match fs::read_dir(&self.config.dir) { Ok(dir) => { - let mut files = Vec::new(); + let mut builders = Vec::new(); let mut initial_length = 0; for f in dir { initial_length += 1; if let Ok(f) = f { - let f = f.path(); - if f.is_file() { - if let Some(f) = f.file_name() { - if let Some(f) = f.to_str() { - files.push(f.to_string()); - } - } + if let Some(f) = SnipBuilder::try_new(f.path()) { + builders.push(f) } } } - info!("Indexed {} / {} files in snippets dir", files.len(), initial_length); + info!("Indexed {} / {} files in snippets dir", builders.len(), initial_length); Some(IndexedSnipptsFolder { config: &self.config, - index: files, + snippets: builders, }) }, Err(err) => { @@ -64,20 +62,22 @@ impl<'a> ValidatedSnipptsFolder<'a> { pub struct IndexedSnipptsFolder<'a>{ config: &'a Config, - index: Vec, + snippets: Vec, } impl<'a> IndexedSnipptsFolder<'a> { pub fn open(self) -> SnipptsFolder { + let snips = self.snippets.into_iter() + .filter_map(|b| b.build()); SnipptsFolder { - index: self.index, + snippets: snips.collect(), creator: SnipCreator::new(self.config.dir.clone()), } } } pub struct SnipptsFolder { - index: Vec, + snippets: Vec, creator: SnipCreator, } @@ -87,8 +87,8 @@ impl SnipptsFolder { } pub fn list(&self) { println!("{}", "Available snippets:".bold().underline()); - for file in &self.index { - println!("{}{}", "> ".cyan(), file); + for snip in &self.snippets { + println!("{}{}\t\t{}", "> ".cyan(), snip.name, snip.tags.join(",").custom_color(CustomColor::new(200, 200, 200)).italic()); } } } diff --git a/rust/snippets/src/snippets/snip.rs b/rust/snippets/src/snippets/snip.rs new file mode 100644 index 0000000..b3db524 --- /dev/null +++ b/rust/snippets/src/snippets/snip.rs @@ -0,0 +1,89 @@ +use std::{fs::{self, Metadata}, path::PathBuf, time::SystemTime}; + +use log::{debug, trace, warn}; + +use super::lang::Lang; + +pub struct Snip { + pub content: String, + pub name: String, + pub last_mod: SystemTime, + pub tags: Vec, + pub lang: Lang, +} + +#[derive(Debug)] +pub struct SnipBuilder { + file: PathBuf, + meta: Metadata, + name: String, +} + +impl SnipBuilder { + /// Gather outer file information (fast) + pub fn try_new(f: PathBuf) -> Option { + debug!("Creating SnipBuilder from {:?}", f); + if !f.is_file() { + warn!("{} is not a file, skipping.", f.display()); + return None; + } + trace!("Starting filename extraction for {:?}.", &f); + let name = f.file_name()?; + let name = name.to_str()?; + let name = name.to_string(); + debug!("Extracted file name from snippet {:?}: {}.", &f, &name); + + trace!("Starting metadata extraction for {:?}.", &f); + let meta = f.metadata().ok()?; + debug!("Extracted metadata from snippet {:?}: {:#?}.", &f, &meta); + + Some(SnipBuilder { + file: f, + name, + meta + }) + } + + /// Parse file content and metadata (slower). + pub fn build(self) -> Option { + trace!("Building snippet {:?}", &self); + + let last_mod = self.meta.modified() + .inspect_err(|err| { + warn!("Cant fetch modified date from snippet {}", self.name); + debug!("{:#?}", err); + }) + .ok()?; + + let file_content = fs::read_to_string(self.file) + .inspect_err(|err| { + warn!("Cant read snippet to string: {}", self.name); + debug!("{:#?}", err); + }) + .ok()?; + + let tags = if let Some(tags) = file_content.lines().next() { + debug!("Parsing tag line {}", &tags); + tags.split(',').map(|e|e.to_string()).collect::>() + } else { + warn!("No tag line in snippet: {}", self.name); + return None; + }; + + let content = file_content.lines() + .skip(2) + .map(|e| e.to_string()) + .collect::>() + .join("\n"); + + + Some(Snip { + content, + name: self.name, + last_mod, + tags, + lang: Lang::Md, + }) + } +} +