Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4a7626f
add examples
Its-Just-Nans Apr 25, 2025
78d0b99
fix: space
Its-Just-Nans Apr 25, 2025
8d2a9c1
fix features flag
Its-Just-Nans Apr 25, 2025
f01e40b
change required feature
Its-Just-Nans Apr 25, 2025
5bdafc6
depencies
Its-Just-Nans Apr 25, 2025
1063992
add examples
Its-Just-Nans Apr 25, 2025
a46a774
fix: space
Its-Just-Nans Apr 25, 2025
c65845e
fix features flag
Its-Just-Nans Apr 25, 2025
7b75db1
change required feature
Its-Just-Nans Apr 25, 2025
5e18f67
depencies
Its-Just-Nans Apr 25, 2025
697e0ac
Merge branch 'manpage-tldr' of github.com:Its-Just-Nans/coreutils int…
Its-Just-Nans May 7, 2025
0b2a48b
update
Its-Just-Nans May 7, 2025
5a1f64b
fix build.rs
Its-Just-Nans May 7, 2025
085f00a
fix ci
Its-Just-Nans May 7, 2025
c9bc1c7
fix not default features
Its-Just-Nans May 7, 2025
afe66ff
fix spaces
Its-Just-Nans May 7, 2025
c163fc4
cargo fmt
Its-Just-Nans May 7, 2025
5b3dfd9
Merge branch 'main' into manpage-tldr
Its-Just-Nans Oct 22, 2025
0d53cdf
cleaner dep
Its-Just-Nans Oct 22, 2025
9579f32
fix move to uudoc
Its-Just-Nans Oct 22, 2025
968e1bd
revert
Its-Just-Nans Oct 22, 2025
86d2bea
fix order
Its-Just-Nans Oct 22, 2025
f290ab3
typo
Its-Just-Nans Oct 22, 2025
aa31b8a
revert
Its-Just-Nans Oct 22, 2025
58ba886
revert
Its-Just-Nans Oct 22, 2025
0c830b1
revert
Its-Just-Nans Oct 22, 2025
ae31158
fix
Its-Just-Nans Oct 22, 2025
14e7635
fix typo
Its-Just-Nans Oct 22, 2025
7eebb4f
cargo clippy
Its-Just-Nans Oct 22, 2025
f72a66f
fix fmt deps
Its-Just-Nans Oct 22, 2025
0dec907
fmt
Its-Just-Nans Oct 23, 2025
bfd283f
clippy again
Its-Just-Nans Oct 23, 2025
3df5a7c
fix: use one function
Its-Just-Nans Oct 23, 2025
c02c04d
Merge branch 'main' into manpage-tldr
Its-Just-Nans Nov 7, 2025
bcf2685
cleaning by removing unwrap
Its-Just-Nans Nov 7, 2025
0c77c1e
fix cargo.toml
Its-Just-Nans Nov 7, 2025
9ee3476
fix tests
Its-Just-Nans Nov 7, 2025
453e6a3
clippy
Its-Just-Nans Nov 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ expensive_tests = []
# "test_risky_names" == enable tests that create problematic file names (would make a network share inaccessible to Windows, breaks SVN on Mac OS, etc.)
test_risky_names = []
# * only build `uudoc` when `--feature uudoc` is activated
uudoc = ["clap_complete", "clap_mangen", "fluent-syntax", "zip"]
uudoc = ["dep:clap_complete", "dep:clap_mangen", "dep:fluent-syntax", "dep:zip"]
## features
## Optional feature for stdbuf
# "feat_external_libstdbuf" == use an external libstdbuf.so for stdbuf instead of embedding it
Expand Down
15 changes: 10 additions & 5 deletions src/bin/coreutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use clap::Command;
use coreutils::validation;
use std::cmp;
use std::ffi::OsString;
use std::io::{self, Write};
use std::process;

use clap::Command;

use coreutils::validation;

const VERSION: &str = env!("CARGO_PKG_VERSION");

include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));

fn usage<T>(utils: &UtilityMap<T>, name: &str) {
println!("{name} {VERSION} (multi-call binary)\n");
println!("Usage: {name} [function [arguments...]]");
println!(" {name} --list\n");
println!(" {name} --list");
println!();
#[cfg(feature = "feat_common_core")]
{
println!("Functions:");
println!(" '<uutils>' [arguments...]");
println!();
}
println!("Options:");
println!(" --list lists all defined functions, one per row\n");
println!("Currently defined functions:\n");
Expand Down
159 changes: 107 additions & 52 deletions src/bin/uudoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ fn gen_coreutils_app<T: Args>(util_map: &UtilityMap<T>) -> clap::Command {
}

/// Generate the manpage for the utility in the first parameter
fn gen_manpage<T: Args>(args: impl Iterator<Item = OsString>, util_map: &UtilityMap<T>) -> ! {
fn gen_manpage<T: Args>(
tldr: &mut Option<ZipArchive<File>>,
args: impl Iterator<Item = OsString>,
util_map: &UtilityMap<T>,
) -> ! {
let all_utilities = validation::get_all_utilities(util_map);

let matches = Command::new("manpage")
Expand All @@ -78,7 +82,13 @@ fn gen_manpage<T: Args>(args: impl Iterator<Item = OsString>, util_map: &Utility
gen_coreutils_app(util_map)
} else {
validation::setup_localization_or_exit(utility);
util_map.get(utility).unwrap().1()
let mut cmd = util_map.get(utility).unwrap().1();
if let Some(zip) = tldr {
if let Ok(examples) = write_zip_examples(zip, utility, false) {
cmd = cmd.after_help(examples);
}
}
cmd
};

let man = Man::new(command);
Expand Down Expand Up @@ -122,19 +132,41 @@ fn gen_completions<T: Args>(args: impl Iterator<Item = OsString>, util_map: &Uti
process::exit(0);
}

/// print tldr error
fn print_tldr_error() {
eprintln!("Warning: No tldr archive found, so the documentation will not include examples.");
eprintln!(
"To include examples in the documentation, download the tldr archive and put it in the docs/ folder."
);
eprintln!();
eprintln!(" curl https://tldr.sh/assets/tldr.zip -o docs/tldr.zip");
eprintln!();
}

/// # Errors
/// Returns an error if the writer fails.
#[allow(clippy::too_many_lines)]
fn main() -> io::Result<()> {
let args: Vec<OsString> = uucore::args_os_filtered().collect();

let mut tldr_zip = File::open("docs/tldr.zip")
.ok()
.and_then(|f| ZipArchive::new(f).ok());

// Check for manpage/completion commands first
if args.len() > 1 {
let command = args.get(1).and_then(|s| s.to_str()).unwrap_or_default();
match command {
"manpage" => {
let args_iter = args.into_iter().skip(2);
gen_manpage(args_iter, &util_map::<Box<dyn Iterator<Item = OsString>>>());
if tldr_zip.is_none() {
print_tldr_error();
}
gen_manpage(
&mut tldr_zip,
args_iter,
&util_map::<Box<dyn Iterator<Item = OsString>>>(),
);
}
"completion" => {
let args_iter = args.into_iter().skip(2);
Expand All @@ -151,20 +183,9 @@ fn main() -> io::Result<()> {
}
}
}
let mut tldr_zip = File::open("docs/tldr.zip")
.ok()
.and_then(|f| ZipArchive::new(f).ok());

if tldr_zip.is_none() {
println!("Warning: No tldr archive found, so the documentation will not include examples.");
println!(
"To include examples in the documentation, download the tldr archive and put it in the docs/ folder."
);
println!();
println!(" curl https://tldr.sh/assets/tldr.zip -o docs/tldr.zip");
println!();
print_tldr_error();
}

let utils = util_map::<Box<dyn Iterator<Item = OsString>>>();
match std::fs::create_dir("docs/src/utils/") {
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
Expand Down Expand Up @@ -431,44 +452,9 @@ impl MDWriter<'_, '_> {
/// Returns an error if the writer fails.
fn examples(&mut self) -> io::Result<()> {
if let Some(zip) = self.tldr_zip {
let content = if let Some(f) =
get_zip_content(zip, &format!("pages/common/{}.md", self.name))
{
f
} else if let Some(f) = get_zip_content(zip, &format!("pages/linux/{}.md", self.name)) {
f
} else {
println!(
"Warning: Could not find tldr examples for page '{}'",
self.name
);
return Ok(());
};

writeln!(self.w, "## Examples")?;
writeln!(self.w)?;
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
if let Some(l) = line.strip_prefix("- ") {
writeln!(self.w, "{l}")?;
} else if line.starts_with('`') {
writeln!(self.w, "```shell\n{}\n```", line.trim_matches('`'))?;
} else if line.is_empty() {
writeln!(self.w)?;
} else {
println!("Not sure what to do with this line:");
println!("{line}");
}
if let Ok(examples) = write_zip_examples(zip, self.name, true) {
writeln!(self.w, "{examples}")?;
}
writeln!(self.w)?;
writeln!(
self.w,
"> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)."
)?;
writeln!(self.w, ">")?;
writeln!(
self.w,
"> Please note that, as uutils is a work in progress, some examples might fail."
)?;
}
Ok(())
}
Expand Down Expand Up @@ -548,3 +534,72 @@ fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Op
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
Some(s)
}

/// Extract examples for tldr.zip. The file docs/tldr.zip must exists
///
/// ```sh
/// curl https://tldr.sh/assets/tldr.zip -o docs/tldr.zip
/// ```
///
/// # Errors
///
/// Returns an error if the tldr.zip file cannot be opened or read
fn write_zip_examples(
archive: &mut ZipArchive<impl Read + Seek>,
name: &str,
output_markdown: bool,
) -> io::Result<String> {
let content = if let Some(f) = get_zip_content(archive, &format!("pages/common/{name}.md")) {
f
} else if let Some(f) = get_zip_content(archive, &format!("pages/linux/{name}.md")) {
f
} else {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Could not find tldr examples for {name}"),
));
};

match format_examples(content, output_markdown) {
Err(e) => Err(std::io::Error::other(format!(
"Failed to format the tldr examples of {name}: {e}"
))),
Ok(s) => Ok(s),
}
}

/// Format examples using std::fmt::Write
fn format_examples(content: String, output_markdown: bool) -> Result<String, std::fmt::Error> {
use std::fmt::Write;
let mut s = String::new();
writeln!(s)?;
writeln!(s, "Examples")?;
writeln!(s)?;
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
if let Some(l) = line.strip_prefix("- ") {
writeln!(s, "{l}")?;
} else if line.starts_with('`') {
if output_markdown {
writeln!(s, "```shell\n{}\n```", line.trim_matches('`'))?;
} else {
writeln!(s, "{}", line.trim_matches('`'))?;
}
} else if line.is_empty() {
writeln!(s)?;
} else {
// println!("Not sure what to do with this line:");
// println!("{line}");
}
}
writeln!(s)?;
writeln!(
s,
"> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)."
)?;
writeln!(s, ">")?;
writeln!(
s,
"> Please note that, as uutils is a work in progress, some examples might fail."
)?;
Ok(s)
}
15 changes: 6 additions & 9 deletions tests/uudoc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ fn test_manpage_generation() {
output.status
);
assert!(
output.stderr.is_empty(),
"stderr should be empty but got: {}",
String::from_utf8_lossy(&output.stderr)
String::from_utf8_lossy(&output.stderr).contains("Warning: No tldr archive found"),
"stderr should contains tldr alert",
);

let output_str = String::from_utf8_lossy(&output.stdout);
Expand All @@ -53,9 +52,8 @@ fn test_manpage_coreutils() {
output.status
);
assert!(
output.stderr.is_empty(),
"stderr should be empty but got: {}",
String::from_utf8_lossy(&output.stderr)
String::from_utf8_lossy(&output.stderr).contains("Warning: No tldr archive found"),
"stderr should contains tldr alert",
);

let output_str = String::from_utf8_lossy(&output.stdout);
Expand Down Expand Up @@ -124,9 +122,8 @@ fn test_manpage_base64() {
output.status
);
assert!(
output.stderr.is_empty(),
"stderr should be empty but got: {}",
String::from_utf8_lossy(&output.stderr)
String::from_utf8_lossy(&output.stderr).contains("Warning: No tldr archive found"),
"stderr should contains tldr alert",
);

let output_str = String::from_utf8_lossy(&output.stdout);
Expand Down
Loading