diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt
index b68da6eb7..e41aba979 100644
--- a/.vscode/cspell.dictionaries/workspace.wordlist.txt
+++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt
@@ -25,6 +25,7 @@ getrandom
globset
itertools
lscolors
+mdbook
memchr
multifilereader
onig
@@ -322,6 +323,7 @@ ucommand
utmpx
uucore
uucore_procs
+uudoc
uumain
uutil
uutils
diff --git a/Cargo.toml b/Cargo.toml
index 14265524f..62e5c50af 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ version = "0.0.12"
authors = ["uutils developers"]
license = "MIT"
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust"
+default-run = "coreutils"
homepage = "https://github.com/uutils/coreutils"
repository = "https://github.com/uutils/coreutils"
@@ -389,3 +390,7 @@ unix_socket = "0.5.0"
[[bin]]
name = "coreutils"
path = "src/bin/coreutils.rs"
+
+[[bin]]
+name = "uudoc"
+path = "src/bin/uudoc.rs"
diff --git a/GNUmakefile b/GNUmakefile
index 12cd95013..b43c3596b 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -279,10 +279,7 @@ endif
build-coreutils:
${CARGO} build ${CARGOFLAGS} --features "${EXES}" ${PROFILE_CMD} --no-default-features
-build-manpages:
- cd $(DOCSDIR) && $(MAKE) man
-
-build: build-coreutils build-pkgs build-manpages
+build: build-coreutils build-pkgs
$(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test))))
@@ -330,14 +327,11 @@ ifeq (${MULTICALL}, y)
cd $(INSTALLDIR_BIN) && $(foreach prog, $(filter-out coreutils, $(INSTALLEES)), \
ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)$(prog) &&) :
$(if $(findstring test,$(INSTALLEES)), cd $(INSTALLDIR_BIN) && ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)[)
- cat $(DOCSDIR)/_build/man/coreutils.1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)coreutils.1.gz
else
$(foreach prog, $(INSTALLEES), \
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
$(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[)
endif
- $(foreach man, $(filter $(INSTALLEES), $(basename $(notdir $(wildcard $(DOCSDIR)/_build/man/*)))), \
- cat $(DOCSDIR)/_build/man/$(man).1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)$(man).1.gz &&) :
mkdir -p $(DESTDIR)$(PREFIX)/share/zsh/site-functions
mkdir -p $(DESTDIR)$(PREFIX)/share/bash-completion/completions
mkdir -p $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d
@@ -359,4 +353,4 @@ endif
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
rm -f $(addprefix $(INSTALLDIR_MAN)/$(PROG_PREFIX),$(addsuffix .1.gz,$(PROGS)))
-.PHONY: all build build-coreutils build-pkgs build-docs test distclean clean busytest install uninstall
+.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall
diff --git a/README.md b/README.md
index 306ca08a7..f9ee6a867 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ have other issues.
Rust provides a good, platform-agnostic way of writing systems utilities that are easy
to compile anywhere, and this is as good a way as any to try and learn it.
+
## Requirements
* Rust (`cargo`, `rustc`)
@@ -252,6 +253,7 @@ To uninstall from a custom parent directory:
# DESTDIR is also supported
$ make PREFIX=/my/path uninstall
```
+
## Test Instructions
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 000000000..f2b5c7168
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,3 @@
+book
+src/utils
+src/SUMMARY.md
diff --git a/docs/arch.rst b/docs/arch.rst
deleted file mode 100644
index 66b516159..000000000
--- a/docs/arch.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. print machine hardware name
-
-====
-arch
-====
-
-.. FIXME: this needs to be autogenerated somehow
-
---------
-Synopsis
---------
-
-``arch`` [OPTION]...
-
------------
-Description
------------
-
-``arch`` is an alias for ``uname -m``. They both print the machine hardware
-name.
-
-An exit code of zero indicates success, whereas anything else means failure.
-For this program, a non-zero exit code generally means the user provided
-invalid options.
-
--h, --help print a help menu for this program displaying accepted
- options and arguments
--v, --version print the version number of this program
diff --git a/docs/book.toml b/docs/book.toml
new file mode 100644
index 000000000..75982ab31
--- /dev/null
+++ b/docs/book.toml
@@ -0,0 +1,9 @@
+[book]
+authors = ["uutils contributors"]
+language = "en"
+multilingual = false
+src = "src"
+title = "uutils Documentation"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/cargo/tree/master/src/doc/src"
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
deleted file mode 100644
index 7f782b12a..000000000
--- a/docs/index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. uutils documentation master file, created by
- sphinx-quickstart on Tue Dec 5 23:20:18 2017.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-..
- spell-checker:ignore (directives) genindex maxdepth modindex toctree ; (misc) quickstart
-
-Welcome to uutils' documentation!
-=================================
-
-.. toctree::
- :maxdepth: 2
- :caption: Contents:
-
- arch
- uutils
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/docs/src/contributing.md b/docs/src/contributing.md
new file mode 100644
index 000000000..79ef4d13b
--- /dev/null
+++ b/docs/src/contributing.md
@@ -0,0 +1 @@
+{{ #include ../../CONTRIBUTING.md }}
\ No newline at end of file
diff --git a/docs/src/index.md b/docs/src/index.md
new file mode 100644
index 000000000..3ea5d913a
--- /dev/null
+++ b/docs/src/index.md
@@ -0,0 +1,20 @@
+# uutils Coreutils Documentation
+
+uutils is an attempt at writing universal (as in cross-platform) CLI
+utilities in [Rust](https://www.rust-lang.org). It is available for
+Linux, Windows, Mac and other platforms.
+
+The API reference for `uucore`, the library of functions shared between
+various utils, is hosted at at
+[docs.rs](https://docs.rs/uucore/latest/uucore/).
+
+uutils is licensed under the [MIT License](https://github.com/uutils/coreutils/blob/main/LICENSE).
+
+## Useful links
+* [Releases](https://github.com/uutils/coreutils/releases)
+* [Source Code](https://github.com/uutils/coreutils)
+* [Issues](https://github.com/uutils/coreutils/issues)
+* [Discord](https://discord.gg/wQVJbvJ)
+
+> Note: This manual is automatically generated from the source code and is
+> a work in progress.
\ No newline at end of file
diff --git a/docs/src/installation.md b/docs/src/installation.md
new file mode 100644
index 000000000..885b5ecb0
--- /dev/null
+++ b/docs/src/installation.md
@@ -0,0 +1,3 @@
+# Installation
+
+{{#include ../../README.md:installation }}
\ No newline at end of file
diff --git a/docs/src/multicall.md b/docs/src/multicall.md
new file mode 100644
index 000000000..5d7b8b169
--- /dev/null
+++ b/docs/src/multicall.md
@@ -0,0 +1,17 @@
+# Multi-call binary
+uutils includes a multi-call binary from which the utils can be invoked. This
+reduces the binary size of the binary and can be useful for portability.
+
+The first argument of the multi-call binary is the util to run, after which
+the regular arguments to the util can be passed.
+
+```shell
+coreutils [util] [util options]
+```
+
+The `--help` flag will print a list of available utils.
+
+## Example
+```
+coreutils ls -l
+```
\ No newline at end of file
diff --git a/docs/theme/favicon.png b/docs/theme/favicon.png
new file mode 100644
index 000000000..1cd1f26ec
Binary files /dev/null and b/docs/theme/favicon.png differ
diff --git a/docs/theme/head.hbs b/docs/theme/head.hbs
new file mode 100644
index 000000000..31cc2dad5
--- /dev/null
+++ b/docs/theme/head.hbs
@@ -0,0 +1,16 @@
+
diff --git a/docs/uutils.rst b/docs/uutils.rst
deleted file mode 100644
index e3b8c6a1a..000000000
--- a/docs/uutils.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. run core utilities
-
-======
-uutils
-======
-
-.. FIXME: this needs to be autogenerated somehow
-
---------
-Synopsis
---------
-
-``uutils`` [OPTION]... [PROGRAM] [OPTION]... [ARGUMENTS]...
-
------------
-Description
------------
-
-``uutils`` is a program that contains other coreutils commands, somewhat
-similar to Busybox.
-
---help, -h print a help menu for PROGRAM displaying accepted options and
- arguments; if PROGRAM was not given, do the same but for this
- program
diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs
new file mode 100644
index 000000000..38e8a0323
--- /dev/null
+++ b/src/bin/uudoc.rs
@@ -0,0 +1,137 @@
+// This file is part of the uutils coreutils package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use clap::App;
+use std::collections::hash_map::HashMap;
+use std::ffi::OsString;
+use std::fs::File;
+use std::io::{self, Write};
+
+include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
+
+fn main() -> io::Result<()> {
+ let utils = util_map::>>();
+ match std::fs::create_dir("docs/src/utils/") {
+ Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
+ x => x,
+ }?;
+
+ let mut summary = File::create("docs/src/SUMMARY.md")?;
+
+ let _ = write!(
+ summary,
+ "# Summary\n\
+ \n\
+ [Introduction](index.md)\n\
+ * [Installation](installation.md)\n\
+ * [Contributing](contributing.md)\n\
+ \n\
+ # Reference\n\
+ * [Multi-call binary](multicall.md)\n",
+ );
+
+ let mut utils = utils.iter().collect::>();
+ utils.sort();
+ for (&name, (_, app)) in utils {
+ if name == "[" {
+ continue;
+ }
+ let p = format!("docs/src/utils/{}.md", name);
+ if let Ok(f) = File::create(&p) {
+ write_markdown(f, &mut app(), name)?;
+ println!("Wrote to '{}'", p);
+ } else {
+ println!("Error writing to {}", p);
+ }
+ writeln!(summary, "* [{0}](utils/{0}.md)", name)?
+ }
+ Ok(())
+}
+
+fn write_markdown(mut w: impl Write, app: &mut App, name: &str) -> io::Result<()> {
+ write!(w, "# {}\n\n", name)?;
+ write_version(&mut w, app)?;
+ write_usage(&mut w, app, name)?;
+ write_description(&mut w, app)?;
+ write_options(&mut w, app)
+}
+
+fn write_version(w: &mut impl Write, app: &App) -> io::Result<()> {
+ writeln!(
+ w,
+ "version: {}
",
+ app.render_version().split_once(' ').unwrap().1
+ )
+}
+
+fn write_usage(w: &mut impl Write, app: &mut App, name: &str) -> io::Result<()> {
+ writeln!(w, "\n```")?;
+ let mut usage: String = app.render_usage().lines().nth(1).unwrap().trim().into();
+ usage = usage.replace(app.get_name(), name);
+ writeln!(w, "{}", usage)?;
+ writeln!(w, "```")
+}
+
+fn write_description(w: &mut impl Write, app: &App) -> io::Result<()> {
+ if let Some(about) = app.get_long_about().or_else(|| app.get_about()) {
+ writeln!(w, "{}", about)
+ } else {
+ Ok(())
+ }
+}
+
+fn write_options(w: &mut impl Write, app: &App) -> io::Result<()> {
+ writeln!(w, "Options
")?;
+ write!(w, "")?;
+ for arg in app.get_arguments() {
+ write!(w, "- ")?;
+ let mut first = true;
+ for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
+ if !first {
+ write!(w, ", ")?;
+ } else {
+ first = false;
+ }
+ write!(w, "
")?;
+ write!(w, "--{}", l)?;
+ if let Some(names) = arg.get_value_names() {
+ write!(
+ w,
+ "={}",
+ names
+ .iter()
+ .map(|x| format!("<{}>", x))
+ .collect::>()
+ .join(" ")
+ )?;
+ }
+ write!(w, "
")?;
+ }
+ for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
+ if !first {
+ write!(w, ", ")?;
+ } else {
+ first = false;
+ }
+ write!(w, "")?;
+ write!(w, "-{}", s)?;
+ if let Some(names) = arg.get_value_names() {
+ write!(
+ w,
+ " {}",
+ names
+ .iter()
+ .map(|x| format!("<{}>", x))
+ .collect::>()
+ .join(" ")
+ )?;
+ }
+ write!(w, "
")?;
+ }
+ writeln!(w, " ")?;
+ writeln!(w, "- \n\n{}\n\n
", arg.get_help().unwrap_or_default())?;
+ }
+ writeln!(w, "
")
+}
diff --git a/src/uu/sum/src/sum.rs b/src/uu/sum/src/sum.rs
index 67bff31b0..1c2b19ba5 100644
--- a/src/uu/sum/src/sum.rs
+++ b/src/uu/sum/src/sum.rs
@@ -19,9 +19,9 @@ use uucore::error::{FromIo, UResult, USimpleError};
use uucore::InvalidEncodingHandling;
static NAME: &str = "sum";
-static USAGE: &str =
- "[OPTION]... [FILE]...\nWith no FILE, or when FILE is -, read standard input.";
-static SUMMARY: &str = "Checksum and count the blocks in a file.";
+static USAGE: &str = "sum [OPTION]... [FILE]...";
+static SUMMARY: &str = "Checksum and count the blocks in a file.\n\
+ With no FILE, or when FILE is -, read standard input.";
fn bsd_sum(mut reader: Box) -> (usize, u16) {
let mut buf = [0; 1024];
diff --git a/src/uu/unexpand/src/unexpand.rs b/src/uu/unexpand/src/unexpand.rs
index 83220a012..812375117 100644
--- a/src/uu/unexpand/src/unexpand.rs
+++ b/src/uu/unexpand/src/unexpand.rs
@@ -22,8 +22,8 @@ use uucore::InvalidEncodingHandling;
static NAME: &str = "unexpand";
static USAGE: &str = "unexpand [OPTION]... [FILE]...";
-static SUMMARY: &str = "Convert blanks in each FILE to tabs, writing to standard output.\n
- With no FILE, or when FILE is -, read standard input.";
+static SUMMARY: &str = "Convert blanks in each FILE to tabs, writing to standard output.\n\
+ With no FILE, or when FILE is -, read standard input.";
const DEFAULT_TABSTOP: usize = 8;