rust_utils/linux/
manpage.rs1use std::{
2 fs,
3 path::Path,
4 collections::HashMap
5};
6use crate::chainable;
7use chrono::{Local, Datelike, Timelike};
8use super::MONTHS;
9
10#[chainable]
12pub struct ManpageBuilder {
13 name: String,
14 short_desc: String,
15 desc: String,
16 author_name: String,
17 author_email: String,
18
19 #[chainable(collapse_option, use_into_impl, doc = "Add in a comment next to the name in the file comment")]
20 name_comment: Option<String>,
21 other_pages: Vec<String>,
22 other_sections: HashMap<String, String>
23}
24
25impl ManpageBuilder {
26 pub fn new(
28 name: &str,
29 short_desc: &str,
30 author_name: &str,
31 author_email: &str,
32 desc: &str
33 ) -> Self {
34 ManpageBuilder {
35 name: name.to_string(),
36 short_desc: short_desc.to_string(),
37 author_name: author_name.to_string(),
38 author_email: author_email.to_string(),
39 desc: desc.replace("\n", "\n.br\n"),
40 name_comment: None,
41 other_pages: vec![],
42 other_sections: HashMap::new()
43 }
44 }
45
46 pub fn other_page(mut self, name: &str) -> Self {
48 self.other_pages.push(name.to_string());
49 self
50 }
51
52 pub fn section(mut self, name: &str, text: &str) -> Self {
56 self.other_sections.insert(name.to_string(), text.replace("\n", "\n.br\n"));
57 self
58 }
59
60 pub fn build<P: AsRef<Path>>(&self, app_ver: &str, path: P) {
62 let date = Local::now().date_naive();
64 let month = MONTHS[date.month() as usize - 1];
65 let day = date.day();
66 let year = date.year();
67 let date_str = format!("{day} {month} {year}");
68 let time = Local::now().time();
69 let hour = time.hour();
70 let minute = time.minute();
71 let second = time.second();
72 let time_str = format!("{hour:02}:{minute:02}:{second:02}");
73
74 let syn_str = if let Some(synopsis) = self.other_sections.get("SYNOPSIS") {
75 format!(
76 ".SH SYNOPSIS\n\
77 {synopsis}\n"
78 )
79 }
80 else { String::new() };
81
82 let examples_str = if let Some(examples) = self.other_sections.get("EXAMPLES") {
83 format!(
84 ".SH EXAMPLES\n\
85 {examples}\n"
86 )
87 }
88 else { String::new() };
89
90 let name_comment = if let Some(ref comment) = self.name_comment {
91 format!(" ({comment})")
92 }
93 else { String::new() };
94
95 let header_str = format!(
96 ".\\\" Manpage for {name}{name_comment}.\n\
97 .\\\" Created on {month} {day}, {year} at {time_str}\n\
98 .TH {name} 1 \"{date_str}\" \"{app_ver}\" \"{name} man page\"\n\
99 .SH NAME\n\
100 {name} \\- {}\n\
101 {syn_str}\
102 .SH DESCRIPTION\n\
103 {}\n\
104 {examples_str}",
105 self.short_desc,
106 self.desc,
107 name = self.name,
108 );
109
110 let author_str = format!(
111 ".SH AUTHOR\n\
112 {} ({})",
113 self.author_name,
114 self.author_email
115 );
116
117 let footer_str = if self.other_pages.len() > 0 {
118 let mut sect_header = String::from(".SH SEE ALSO\n");
119 for (i, other_page) in self.other_pages.iter().enumerate() {
120 sect_header.push_str(&format!("{other_page}(1)\n"));
121
122 if i < self.other_pages.len() - 1{
123 sect_header.push_str(".br\n");
124 }
125 }
126
127 format!("{sect_header}{author_str}")
128 }
129 else { author_str };
130
131 let mut body_str = String::new();
132
133 for (sect_title, sect_body) in &self.other_sections {
134 if sect_title != "SYNOPSIS" && sect_title != "EXAMPLES" {
135 body_str.push_str(&format!(
136 ".SH {sect_title}\n\
137 {sect_body}\n"
138 ));
139 }
140 }
141
142 let file_str = format!("{header_str}{body_str}{footer_str}");
143 fs::remove_file(&path).unwrap_or(());
144 fs::write(&path, &file_str).unwrap();
145 }
146}