diff --git a/ecosystem/rust/importer/src/lib.rs b/ecosystem/rust/importer/src/lib.rs index 3c2ea05a..64174553 100644 --- a/ecosystem/rust/importer/src/lib.rs +++ b/ecosystem/rust/importer/src/lib.rs @@ -17,7 +17,7 @@ impl LibraryGenerator { let file = file_set.entry(PathBuf::from("Cargo.toml")); let mut template = Template::new(); template.register_template("project", include_str!("templates/Cargo.hbs"))?; - let template = template.render("project", &library)?; + let template = template.render("project", library)?; let root = file.section("root"); root.write(template); Ok(()) @@ -26,7 +26,7 @@ impl LibraryGenerator { pub fn generate_lib_file(&self, library: &Library, file_set: &mut FileSet) -> Result<()> { let file = file_set.entry(PathBuf::from("src").join("lib.rs")); let section = file.section("documentation"); - section.writeln(library.metadata.description.split("\n").map(|s| format!("//! {}", s)).collect::>().join("\n")); + section.writeln(library.metadata.description.split('\n').map(|s| format!("//! {}", s)).collect::>().join("\n")); Ok(()) } diff --git a/ligen/generator/src/generator/file_generator/file.rs b/ligen/generator/src/generator/file_generator/file.rs index 971ec65b..9cec52da 100644 --- a/ligen/generator/src/generator/file_generator/file.rs +++ b/ligen/generator/src/generator/file_generator/file.rs @@ -5,10 +5,38 @@ use ligen_utils::fs::write_file; use std::path::{Path, PathBuf}; use std::collections::{HashMap, BTreeMap}; +/// Structure representing a file path and its content. +#[derive(Debug, Clone, PartialEq, Shrinkwrap)] +#[shrinkwrap(mutable)] +pub struct File { + /// File path. + pub path: PathBuf, + /// File Section. + #[shrinkwrap(main_field)] + pub section: FileSection +} + +impl File { + /// Creates a new file with the specified path and content. + pub fn new(path: impl AsRef) -> Self { + let path = path.as_ref().to_path_buf(); + let section = Default::default(); + Self { path, section } + } + + /// Saves the file. + pub fn save(&self) -> Result<()> { + write_file(&self.path, self.content()) + } +} + + #[derive(Default, Debug, Clone, PartialEq)] pub struct FileSection { /// File section content. - pub content: String + content: Vec, + sections: BTreeMap, + order: Vec } impl FileSection { @@ -17,37 +45,34 @@ impl FileSection { Self::default() } - /// Writes the content to the file buffer. - pub fn write>(&mut self, content: S) { - self.content.push_str(content.as_ref()); + /// Creates a new FileSection from a template. + pub fn from_template(template: impl AsRef) -> Result { + let mut section = Self::new(); + let template = template.as_ref(); + const SECTION_START: &str = "[section("; + const SECTION_END: &str = ")]"; + for (index, _) in template.match_indices(SECTION_START) { + let index = index + SECTION_START.len(); + let index_end = template[index..] + .find(SECTION_END) + .ok_or_else(|| Error::Message("Failed to parse template: missing section end.".to_string()))? + index; + let section_name = &template[index..index_end]; + section.section(section_name); + } + Ok(section) } - /// Writes the content to the file buffer and adds a new line. - pub fn writeln>(&mut self, content: S) { - self.content.push_str(content.as_ref()); - self.content.push('\n'); - } -} - -/// Structure representing a file path and its content. -#[derive(Debug, Clone, PartialEq)] -pub struct File { - /// File path. - pub path: PathBuf, - /// File sections. - pub sections: BTreeMap, - order: Vec -} - -impl File { - /// Creates a new file with the specified path and content. - pub fn new(path: impl AsRef) -> Self { - let sections = Default::default(); - let path = path.as_ref().to_path_buf(); - let order = Default::default(); - Self { path, sections, order } + /// Gets content. + pub fn content(&self) -> String { + let mut content = self.content.join(""); + for section in &self.order { + if let Some(section) = self.sections.get(section) { + content.push_str(§ion.content()); + } + } + content } - + /// Gets or creates a new section with the specified name. pub fn section(&mut self, name: impl AsRef) -> &mut FileSection { self @@ -59,21 +84,29 @@ impl File { }) } - /// Gets content. - pub fn content(&self) -> String { - let mut content = String::new(); - for section in &self.order { - if let Some(section) = self.sections.get(section) { - content.push_str(§ion.content); - } - } - content + /// Writes the content to the file section at the specified index. + pub fn indexed_write>(&mut self, index: usize, content: S) { + self.content.insert(index, content.as_ref().to_string()) } - /// Saves the file. - pub fn save(&self) -> Result<()> { - write_file(&self.path, self.content()) + /// Writes the content to the file section at the specified index and adds a new line. + pub fn indexed_writeln>(&mut self, index: usize, content: S) { + let mut string = content.as_ref().to_string(); + string.push('\n'); + self.indexed_write(index, string); + } + + /// Writes the content to the file buffer. + pub fn write>(&mut self, content: S) { + self.content.push(content.as_ref().to_string()); } + + /// Writes the content to the file buffer and adds a new line. + pub fn writeln>(&mut self, content: S) { + let mut string = content.as_ref().to_string(); + string.push('\n'); + self.content.push(string); + } } /// Structure representing all the file set to be generated. @@ -101,6 +134,9 @@ impl FileSet { #[cfg(test)] mod tests { + use crate::prelude::*; + use crate::file_generator::FileSection; + use super::File; #[test] @@ -110,4 +146,68 @@ mod tests { file.section("a").write("A"); assert_eq!(file.content(), "BA"); } -} \ No newline at end of file + + #[test] + fn section() { + let mut section = FileSection::new(); + section.writeln("//! This is a Rust"); + section.writeln("//! documentation."); + section.section("sub1").write("//! This is a sub-section and "); + section.section("sub2").writeln("//! This is another sub-section."); + section.section("sub1").writeln("we can add to it later."); + assert_eq!(section.content(), "//! This is a Rust\n//! documentation.\n//! This is a sub-section and we can add to it later.\n//! This is another sub-section.\n"); + } + + #[test] + fn deep_section() { + let mut section = FileSection::new(); + section.section("attribute::begin").write("#[ligen("); + section.section("attribute::parameters").write("name = \"test\""); + section.section("attribute::parameters").write(", truth = true"); + section.section("attribute::end").writeln(")]"); + assert_eq!(section.content(), "#[ligen(name = \"test\", truth = true)]\n"); + + let mut section = FileSection::new(); + for name in ["attribute::begin", "attribute::parameters", "attribute::end"] { + section.section(name); + } + section.section("attribute::begin").write("#[ligen("); + section.section("attribute::end").writeln(")]"); + section.section("attribute::parameters").write("name = \"test\""); + section.section("attribute::parameters").write(", truth = true"); + assert_eq!(section.content(), "#[ligen(name = \"test\", truth = true)]\n"); + } + + #[test] + fn template() -> Result<()> { + let template = "[section(attribute::begin)][section(attribute::parameters)][section(attribute::end)]"; + let mut section = FileSection::from_template(template)?; + assert_eq!(section.order, vec!["attribute::begin", "attribute::parameters", "attribute::end"]); + section.section("attribute::begin").write("#[ligen("); + section.section("attribute::end").writeln(")]"); + section.section("attribute::parameters").write("name = \"test\""); + section.section("attribute::parameters").write(", truth = true"); + assert_eq!(section.content(), "#[ligen(name = \"test\", truth = true)]\n"); + Ok(()) + } + + // #[test] + // fn template_with_content() -> Result<()> { + // let template = "before[section(begin)]content[section(end)]after"; + // let mut section = FileSection::from_template(template)?; + // assert_eq!(section.order, vec!["begin", "end"]); + // section.section("begin").write("-begin-"); + // section.section("end").write("-end-"); + // assert_eq!(section.content(), "before-begin-content-end-after"); + // Ok(()) + // } + + #[test] + fn indexed_section() { + let mut section = FileSection::new(); + section.indexed_write(0, "First"); + section.indexed_write(1, ", Third"); + section.indexed_write(1, ", Second"); + assert_eq!(section.content(), "First, Second, Third"); + } +}