Skip to content

Commit 6cc245d

Browse files
committed
Fix the doc generation and remove uuhelp_parser
1 parent a188459 commit 6cc245d

File tree

10 files changed

+53
-408
lines changed

10 files changed

+53
-408
lines changed

Cargo.lock

Lines changed: 1 addition & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ expensive_tests = []
3333
# "test_risky_names" == enable tests that create problematic file names (would make a network share inaccessible to Windows, breaks SVN on Mac OS, etc.)
3434
test_risky_names = []
3535
# * only build `uudoc` when `--feature uudoc` is activated
36-
uudoc = ["zip", "dep:uuhelp_parser"]
36+
uudoc = ["zip", "dep:fluent-syntax"]
3737
## features
3838
## Optional feature for stdbuf
3939
# "feat_external_libstdbuf" == use an external libstdbuf.so for stdbuf instead of embedding it
@@ -282,7 +282,6 @@ members = [
282282
"src/uu/stdbuf/src/libstdbuf",
283283
"src/uucore",
284284
"src/uucore_procs",
285-
"src/uuhelp_parser",
286285
"tests/benches/factor",
287286
"tests/uutests",
288287
# "fuzz", # TODO
@@ -415,8 +414,8 @@ phf.workspace = true
415414
selinux = { workspace = true, optional = true }
416415
textwrap.workspace = true
417416
zip = { workspace = true, optional = true }
417+
fluent-syntax = { workspace = true, optional = true }
418418

419-
uuhelp_parser = { optional = true, version = "0.2.2", path = "src/uuhelp_parser" }
420419

421420
# * uutils
422421
uu_test = { optional = true, version = "0.2.2", package = "uu_test", path = "src/uu/test" }

src/bin/uudoc.rs

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// spell-checker:ignore tldr uuhelp
66

77
use clap::Command;
8+
use fluent_syntax::ast::{Entry, Message, Pattern};
9+
use fluent_syntax::parser;
810
use std::collections::HashMap;
911
use std::ffi::OsString;
1012
use std::fs::File;
@@ -140,7 +142,7 @@ fn main() -> io::Result<()> {
140142
}
141143
let p = format!("docs/src/utils/{name}.md");
142144

143-
let markdown = File::open(format!("src/uu/{name}/{name}.md"))
145+
let fluent = File::open(format!("src/uu/{name}/locales/en-US.ftl"))
144146
.and_then(|mut f: File| {
145147
let mut s = String::new();
146148
f.read_to_string(&mut s)?;
@@ -155,7 +157,7 @@ fn main() -> io::Result<()> {
155157
name,
156158
tldr_zip: &mut tldr_zip,
157159
utils_per_platform: &utils_per_platform,
158-
markdown,
160+
fluent,
159161
}
160162
.markdown()?;
161163
println!("Wrote to '{p}'");
@@ -173,7 +175,7 @@ struct MDWriter<'a, 'b> {
173175
name: &'a str,
174176
tldr_zip: &'b mut Option<ZipArchive<File>>,
175177
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
176-
markdown: Option<String>,
178+
fluent: Option<String>,
177179
}
178180

179181
impl MDWriter<'_, '_> {
@@ -189,6 +191,33 @@ impl MDWriter<'_, '_> {
189191
self.examples()
190192
}
191193

194+
/// Extract value for a Fluent key from the .ftl content
195+
fn extract_fluent_value(&self, key: &str) -> Option<String> {
196+
let content = self.fluent.as_ref()?;
197+
let resource = parser::parse(content.clone()).ok()?;
198+
199+
for entry in resource.body {
200+
if let Entry::Message(Message {
201+
id,
202+
value: Some(Pattern { elements }),
203+
..
204+
}) = entry
205+
{
206+
if id.name == key {
207+
// Simple text extraction - just concatenate text elements
208+
let mut result = String::new();
209+
for element in elements {
210+
if let fluent_syntax::ast::PatternElement::TextElement { value } = element {
211+
result.push_str(&value);
212+
}
213+
}
214+
return Some(result);
215+
}
216+
}
217+
}
218+
None
219+
}
220+
192221
/// # Errors
193222
/// Returns an error if the writer fails.
194223
fn additional(&mut self) -> io::Result<()> {
@@ -237,10 +266,7 @@ impl MDWriter<'_, '_> {
237266
/// # Errors
238267
/// Returns an error if the writer fails.
239268
fn usage(&mut self) -> io::Result<()> {
240-
if let Some(markdown) = &self.markdown {
241-
let usage = uuhelp_parser::parse_usage(markdown);
242-
let usage = usage.replace("{}", self.name);
243-
269+
if let Some(usage) = self.extract_fluent_value(&format!("{}-usage", self.name)) {
244270
writeln!(self.w, "\n```")?;
245271
writeln!(self.w, "{usage}")?;
246272
writeln!(self.w, "```")
@@ -252,8 +278,8 @@ impl MDWriter<'_, '_> {
252278
/// # Errors
253279
/// Returns an error if the writer fails.
254280
fn about(&mut self) -> io::Result<()> {
255-
if let Some(markdown) = &self.markdown {
256-
writeln!(self.w, "{}", uuhelp_parser::parse_about(markdown))
281+
if let Some(about) = self.extract_fluent_value(&format!("{}-about", self.name)) {
282+
writeln!(self.w, "{about}")
257283
} else {
258284
Ok(())
259285
}
@@ -262,13 +288,11 @@ impl MDWriter<'_, '_> {
262288
/// # Errors
263289
/// Returns an error if the writer fails.
264290
fn after_help(&mut self) -> io::Result<()> {
265-
if let Some(markdown) = &self.markdown {
266-
if let Some(after_help) = uuhelp_parser::parse_section("after help", markdown) {
267-
return writeln!(self.w, "\n\n{after_help}");
268-
}
291+
if let Some(after_help) = self.extract_fluent_value(&format!("{}-after-help", self.name)) {
292+
writeln!(self.w, "\n\n{after_help}")
293+
} else {
294+
Ok(())
269295
}
270-
271-
Ok(())
272296
}
273297

274298
/// # Errors
@@ -368,13 +392,17 @@ impl MDWriter<'_, '_> {
368392
write!(self.w, "</code>")?;
369393
}
370394
writeln!(self.w, "</dt>")?;
395+
let help_text = arg.get_help().unwrap_or_default().to_string();
396+
// Try to resolve Fluent key if it looks like one, otherwise use as-is
397+
let resolved_help = if help_text.starts_with(&format!("{}-help-", self.name)) {
398+
self.extract_fluent_value(&help_text).unwrap_or(help_text)
399+
} else {
400+
help_text
401+
};
371402
writeln!(
372403
self.w,
373404
"<dd>\n\n{}\n\n</dd>",
374-
arg.get_help()
375-
.unwrap_or_default()
376-
.to_string()
377-
.replace('\n', "<br />")
405+
resolved_help.replace('\n', "<br />")
378406
)?;
379407
}
380408
writeln!(self.w, "</dl>\n")

src/uucore_procs/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# spell-checker:ignore uuhelp
21
[package]
32
name = "uucore_procs"
43
description = "uutils ~ 'uucore' proc-macros"
@@ -17,4 +16,3 @@ proc-macro = true
1716
[dependencies]
1817
proc-macro2 = "1.0.81"
1918
quote = "1.0.36"
20-
uuhelp_parser = { path = "../uuhelp_parser", version = "0.2.2" }

src/uucore_procs/src/lib.rs

Lines changed: 2 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55
//
6-
// spell-checker:ignore backticks uuhelp SIGSEGV
6+
// spell-checker:ignore SIGSEGV
77

88
//! A collection of procedural macros for uutils.
99
#![deny(missing_docs)]
1010

11-
use std::{fs::File, io::Read, path::PathBuf};
12-
13-
use proc_macro::{Literal, TokenStream, TokenTree};
11+
use proc_macro::TokenStream;
1412
use quote::quote;
1513

1614
//## rust proc-macro background info
@@ -48,127 +46,3 @@ pub fn main(_args: TokenStream, stream: TokenStream) -> TokenStream {
4846

4947
TokenStream::from(new)
5048
}
51-
52-
// FIXME: This is currently a stub. We could do much more here and could
53-
// even pull in a full markdown parser to get better results.
54-
/// Render markdown into a format that's easier to read in the terminal.
55-
///
56-
/// For now, all this function does is remove backticks.
57-
/// Some ideas for future improvement:
58-
/// - Render headings as bold
59-
/// - Convert triple backticks to indented
60-
/// - Printing tables in a nice format
61-
fn render_markdown(s: &str) -> String {
62-
s.replace('`', "")
63-
}
64-
65-
/// Get the about text from the help file.
66-
///
67-
/// The about text is assumed to be the text between the first markdown
68-
/// code block and the next header, if any. It may span multiple lines.
69-
#[proc_macro]
70-
pub fn help_about(input: TokenStream) -> TokenStream {
71-
let input: Vec<TokenTree> = input.into_iter().collect();
72-
let filename = get_argument(&input, 0, "filename");
73-
let text: String = uuhelp_parser::parse_about(&read_help(&filename));
74-
assert!(
75-
!text.is_empty(),
76-
"About text not found! Make sure the markdown format is correct"
77-
);
78-
TokenTree::Literal(Literal::string(&text)).into()
79-
}
80-
81-
/// Get the usage from the help file.
82-
///
83-
/// The usage is assumed to be surrounded by markdown code fences. It may span
84-
/// multiple lines. The first word of each line is assumed to be the name of
85-
/// the util and is replaced by "{}" so that the output of this function can be
86-
/// used with `uucore::format_usage`.
87-
#[proc_macro]
88-
pub fn help_usage(input: TokenStream) -> TokenStream {
89-
let input: Vec<TokenTree> = input.into_iter().collect();
90-
let filename = get_argument(&input, 0, "filename");
91-
let text: String = uuhelp_parser::parse_usage(&read_help(&filename));
92-
assert!(
93-
!text.is_empty(),
94-
"Usage text not found! Make sure the markdown format is correct"
95-
);
96-
TokenTree::Literal(Literal::string(&text)).into()
97-
}
98-
99-
/// Reads a section from a file of the util as a `str` literal.
100-
///
101-
/// It reads from the file specified as the second argument, relative to the
102-
/// crate root. The contents of this file are read verbatim, without parsing or
103-
/// escaping. The name of the help file should match the name of the util.
104-
/// I.e. numfmt should have a file called `numfmt.md`. By convention, the file
105-
/// should start with a top-level section with the name of the util. The other
106-
/// sections must start with 2 `#` characters. Capitalization of the sections
107-
/// does not matter. Leading and trailing whitespace of each section will be
108-
/// removed.
109-
///
110-
/// Example:
111-
/// ```md
112-
/// # numfmt
113-
/// ## About
114-
/// Convert numbers from/to human-readable strings
115-
///
116-
/// ## Long help
117-
/// This text will be the long help
118-
/// ```
119-
///
120-
/// ```rust,ignore
121-
/// help_section!("about", "numfmt.md");
122-
/// ```
123-
#[proc_macro]
124-
pub fn help_section(input: TokenStream) -> TokenStream {
125-
let input: Vec<TokenTree> = input.into_iter().collect();
126-
let section = get_argument(&input, 0, "section");
127-
let filename = get_argument(&input, 1, "filename");
128-
129-
if let Some(text) = uuhelp_parser::parse_section(&section, &read_help(&filename)) {
130-
let rendered = render_markdown(&text);
131-
TokenTree::Literal(Literal::string(&rendered)).into()
132-
} else {
133-
panic!(
134-
"The section '{section}' could not be found in the help file. Maybe it is spelled wrong?"
135-
)
136-
}
137-
}
138-
139-
/// Get an argument from the input vector of `TokenTree`.
140-
///
141-
/// Asserts that the argument is a string literal and returns the string value,
142-
/// otherwise it panics with an error.
143-
fn get_argument(input: &[TokenTree], index: usize, name: &str) -> String {
144-
// Multiply by two to ignore the `','` in between the arguments
145-
let string = match &input.get(index * 2) {
146-
Some(TokenTree::Literal(lit)) => lit.to_string(),
147-
Some(_) => panic!("Argument {index} should be a string literal."),
148-
None => panic!("Missing argument at index {index} for {name}"),
149-
};
150-
151-
string
152-
.parse::<String>()
153-
.unwrap()
154-
.strip_prefix('"')
155-
.unwrap()
156-
.strip_suffix('"')
157-
.unwrap()
158-
.to_string()
159-
}
160-
161-
/// Read the help file
162-
fn read_help(filename: &str) -> String {
163-
let mut content = String::new();
164-
165-
let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
166-
path.push(filename);
167-
168-
File::open(path)
169-
.unwrap()
170-
.read_to_string(&mut content)
171-
.unwrap();
172-
173-
content
174-
}

src/uuhelp_parser/Cargo.toml

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/uuhelp_parser/LICENSE

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)