reorganize template format members

This commit is contained in:
postscriptum 2025-07-04 15:23:35 +03:00
parent 475e23c774
commit 25186136bc
4 changed files with 104 additions and 118 deletions

View file

@ -1,12 +1,11 @@
mod attachment; mod attachment;
mod format;
pub mod response; pub mod response;
pub mod source; pub mod source;
mod template;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use attachment::Attachment; use attachment::Attachment;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use format::Format;
use response::{Clean, Sync, change::Change}; use response::{Clean, Sync, change::Change};
use source::Source; use source::Source;
use std::{ use std::{
@ -15,13 +14,14 @@ use std::{
path::PathBuf, path::PathBuf,
str::FromStr, str::FromStr,
}; };
use template::Template;
pub struct Nex { pub struct Nex {
attachment: Attachment, attachment: Attachment,
filename: String, filename: String,
format: Format,
is_cleanup: bool, is_cleanup: bool,
is_debug: bool, is_debug: bool,
template: Template,
users: HashMap<String, PathBuf>, users: HashMap<String, PathBuf>,
} }
@ -48,13 +48,13 @@ impl Nex {
fs::create_dir_all(&p)?; fs::create_dir_all(&p)?;
users.insert(u.clone(), p); users.insert(u.clone(), p);
} }
// init document format // init document template formatter
let format = Format::init(&filename, pattern, time_format); let template = Template::init(&filename, pattern, time_format);
Ok(Self { Ok(Self {
attachment: Attachment::init(attachment_mode)?, attachment: Attachment::init(attachment_mode)?,
filename, filename,
format, template,
is_cleanup, is_cleanup,
is_debug, is_debug,
users, users,
@ -154,7 +154,7 @@ impl Nex {
}; };
fs::write( fs::write(
&f, &f,
self.format.to_string( self.template.build(
updated, updated,
content, content,
link, link,

View file

@ -1,111 +0,0 @@
use chrono::{DateTime, Utc};
pub enum Format {
/// Format as [Gemtext](https://geminiprotocol.net/docs/gemtext.gmi)
/// * detected in case, when the `format_filename` option has `.gmi` or `.gemtext` suffix in pattern
Gemtext {
pattern: String,
time_format: String,
},
/// It is useful to enable clickable links
/// * detected in case, when the `format_filename` option has trailing slash in pattern
/// * the server should support appending a trailing slash in this case
Dir {
pattern: String,
time_format: String,
},
/// Ignore markdown
Plain {
pattern: String,
time_format: String,
},
}
impl Format {
pub fn init(filename: &str, pattern: String, time_format: String) -> Self {
if filename.ends_with('/') {
Format::Dir {
pattern,
time_format,
}
} else if filename.ends_with(".gmi") | filename.ends_with(".gemtext") {
Format::Gemtext {
pattern,
time_format,
}
} else {
Format::Plain {
pattern,
time_format,
}
}
}
pub fn to_string(
&self,
updated: Option<DateTime<Utc>>,
content: String,
link: String,
tags: Option<Vec<String>>,
attachments: Option<Vec<(String, Option<String>)>>,
) -> String {
match self {
// implement separated templates @TODO
Self::Dir {
pattern,
time_format,
}
| Self::Gemtext {
pattern,
time_format,
}
| Self::Plain {
pattern,
time_format,
} => pattern
.replace(
"{content}",
&if pattern.contains("{tags}") {
content.replace("#", "")
} else {
content
},
)
.replace(
"{attachments}",
&attachments
.map(|a| {
let mut b = Vec::with_capacity(a.len());
b.push("\n".to_string());
for (link, alt) in a {
let mut t = Vec::with_capacity(2);
t.push(if matches!(self, Self::Dir { .. }) {
format!("=> ../{link}")
} else {
format!("=> {link}")
});
if let Some(text) = alt {
t.push(text)
}
b.push(t.join(" "))
}
b.join("\n")
})
.unwrap_or_default(),
)
.replace(
"{tags}",
&tags
.map(|t| format!("\n\n{}", t.join(", ")))
.unwrap_or_default(),
)
.replace("{link}", &format!("\n\n=> {link}"))
.replace(
"{updated}",
&updated
.map(|t| format!("\n\n{}", t.format(time_format)))
.unwrap_or_default(),
),
}
}
}

74
src/nex/template.rs Normal file
View file

@ -0,0 +1,74 @@
mod format;
use chrono::{DateTime, Utc};
use format::Format;
pub struct Template {
format: Format,
pattern: String,
time_format: String,
}
impl Template {
pub fn init(filename: &str, pattern: String, time_format: String) -> Self {
Self {
format: Format::init(filename),
pattern,
time_format,
}
}
pub fn build(
&self,
updated: Option<DateTime<Utc>>,
content: String,
link: String,
tags: Option<Vec<String>>,
attachments: Option<Vec<(String, Option<String>)>>,
) -> String {
// implement separated templates @TODO
self.pattern
.replace(
"{content}",
&if self.pattern.contains("{tags}") {
content.replace("#", "")
} else {
content
},
)
.replace(
"{attachments}",
&attachments
.map(|a| {
let mut b = Vec::with_capacity(a.len());
b.push("\n".to_string());
for (link, alt) in a {
let mut t = Vec::with_capacity(2);
t.push(if matches!(self.format, Format::Dir) {
format!("=> ../{link}")
} else {
format!("=> {link}")
});
if let Some(text) = alt {
t.push(text)
}
b.push(t.join(" "))
}
b.join("\n")
})
.unwrap_or_default(),
)
.replace(
"{tags}",
&tags
.map(|t| format!("\n\n{}", t.join(", ")))
.unwrap_or_default(),
)
.replace("{link}", &format!("\n\n=> {link}"))
.replace(
"{updated}",
&updated
.map(|t| format!("\n\n{}", t.format(&self.time_format)))
.unwrap_or_default(),
)
}
}

View file

@ -0,0 +1,23 @@
pub enum Format {
/// [Gemtext](https://geminiprotocol.net/docs/gemtext.gmi)
/// * detected in case, when the `format_filename` option has `.gmi` or `.gemtext` suffix in pattern
Gemtext,
/// Enables clickable links
/// * detected in case, when the `format_filename` option has trailing slash in pattern
/// * the server should support appending a trailing slash in this case
Dir,
/// Ignore markdown
Plain,
}
impl Format {
pub fn init(filename: &str) -> Self {
if filename.ends_with('/') {
Self::Dir
} else if filename.ends_with(".gmi") | filename.ends_with(".gemtext") {
Self::Gemtext
} else {
Self::Plain
}
}
}