Skip to content

Commit

Permalink
Merge pull request #68 from tertsdiepraam/guide-docs
Browse files Browse the repository at this point in the history
Guide-level documentation
  • Loading branch information
tertsdiepraam authored Dec 19, 2023
2 parents 645f700 + 49ede19 commit 5cdae9b
Show file tree
Hide file tree
Showing 13 changed files with 849 additions and 241 deletions.
13 changes: 9 additions & 4 deletions derive/src/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ pub fn complete(args: &[Argument], file: &Option<String>) -> TokenStream {
continue;
}

// If none of the flags take an argument, we won't need ValueHint
// based on that type. So we should not attempt to call `value_hint`
// on it.
let any_flag_takes_argument =
short.iter().any(|f| f.value != Value::No) && long.iter().any(|f| f.value != Value::No);

let short: Vec<_> = short
.iter()
.map(|Flag { flag, value }| {
Expand Down Expand Up @@ -69,10 +75,9 @@ pub fn complete(args: &[Argument], file: &Option<String>) -> TokenStream {
})
.collect();

let hint = if let Some(ty) = field {
quote!(Some(<#ty>::value_hint()))
} else {
quote!(None)
let hint = match (field, any_flag_takes_argument) {
(Some(ty), true) => quote!(Some(<#ty>::value_hint())),
_ => quote!(None),
};

arg_specs.push(quote!(
Expand Down
5 changes: 5 additions & 0 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Derive macros for `uutils_args`. All items here are documented in that
//! crate.
mod argument;
mod attributes;
mod complete;
Expand All @@ -18,6 +21,7 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data::Enum, DeriveInput};

/// Documentation for this can be found in `uutils_args`.
#[proc_macro_derive(Arguments, attributes(arg, arguments))]
pub fn arguments(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down Expand Up @@ -110,6 +114,7 @@ pub fn arguments(input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}

/// Documentation for this can be found in `uutils_args`.
#[proc_macro_derive(Value, attributes(value))]
pub fn value(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down
213 changes: 0 additions & 213 deletions design/design.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,25 @@ Some utils take positional arguments, which might be required.

### Deprecated syntax `+N` and `-N`

Some utils (e.g. `head`, `tail`, `kill`, `fold` and `uniq`) support an old deprecated syntax where numbers can be directly passed as arguments as a shorthand. For example, `uniq +5` is a shorthand for `uniq -s 5` and `uniq -5` is short for `uniq -f 5`.
Some utils (e.g. `head`, `tail`, `kill`, `fold` and `uniq`) support an old
deprecated syntax where numbers can be directly passed as arguments as a
shorthand. For example, `uniq +5` is a shorthand for `uniq -s 5` and `uniq -5`
is short for `uniq -f 5`.

These all behave slightly differently.
1. `head` and `tail` only accept this if it is the first argument and either 1 or 2 arguments are given.
2. In `fold` the `-N` must be standalone (e.g. `-10b` is rejected), but can appear at any position.
3. In `kill`, the same rules as `fold` apply, but it can also be a name instead of a number.
4. In `uniq`, the syntax does not need to stand alone and is additive in a weird way, because they hack `-22` as `-2 -2` so each flag `-1...-9` multiplies the previous by 10 and adds itself. I'm not sure that we need to support this. Doing something like what `fold` and `kill` do is probably fine. Also note that to make it extra confusing, the `+` variant works like `fold`.

1. `head` and `tail` only accept this if it is the first argument and either 1
or 2 arguments are given.
2. In `fold` the `-N` must be standalone (e.g. `-10b` is rejected), but can
appear at any position.
3. In `kill`, the same rules as `fold` apply, but it can also be a name instead
of a number.
4. In `uniq`, the syntax does not need to stand alone and is additive in a weird
way, because they hack `-22` as `-2 -2` so each flag `-1...-9` multiplies the
previous by 10 and adds itself. I'm not sure that we need to support this.
Doing something like what `fold` and `kill` do is probably fine. Also note
that to make it extra confusing, the `+` variant works like `fold`.
5. `pr` the behaviour is similar to `uniq`.
6. `split` seems to be somewhere between `uniq` and `fold`. It accepts things like `-x10x` correctly, but it doesn't do the additive thing from `uniq` across multiple occurrences. Basically, it's very clever and cursed.
6. `split` seems to be somewhere between `uniq` and `fold`. It accepts things
like `-x10x` correctly, but it doesn't do the additive thing from `uniq`
across multiple occurrences. Basically, it's very clever and cursed.
17 changes: 9 additions & 8 deletions design/README.md → docs/design/design.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# `uutils-args` Design Docs
# Design

This is a series of design documents, explaining the various design goals and
decisions. Before diving in, let's lay out the design goals of this project.
This module contains some documents about the design of this library. In particular, it details the different kinds of arguments that are present in the coreutils and the difficulties that `clap` presents when implementing these arguments.

The primary design considerations of this library are:

- Must support all options in GNU coreutils.
- Must support a many-to-many relationship between options and settings.
Expand All @@ -14,10 +15,10 @@ decisions. Before diving in, let's lay out the design goals of this project.
fewer features to support.
- Use outside uutils is possible but not prioritized. Hence, configurability
beyond the coreutils is not necessary.
- Errors must be at least as good as GNU's, but may be different (hopefully improved).
- Errors must be at least as good as GNU's, but may be different (hopefully
improved).

## Pages
## Chapters

1. [Arguments in coreutils](arguments_in_coreutils.md)
2. [Problems with `clap` and other parsers](problems_with_clap.md)
3. [Library design](design.md) (TODO once the design settles)
1. [Arguments in the coreutils](design::coreutils)
2. [Problems with `clap`](design::problems)
20 changes: 11 additions & 9 deletions design/problems_with_clap.md → docs/design/problems_with_clap.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ inspiration from them.
Before I continue, I want to note that these are not (always) general problems
with `clap`. They are problems that show up when you want to implement the
coreutils with it. The coreutils have some weird behaviour that you won't have
to deal with in a new project. `clap` is still a really good library and you
to deal with in a new project. `clap` is still a great library, and you
should probably use it over this library, unless you need compatibility with GNU
utils.
utilities.

## Problem 1: No many-to-many relationship between arguments and settings

This is the biggest issue we have with `clap`. In `clap`, it is assumed that
options do not interfere with each other. This means that _partially overriding_
options are really hard to support. `rm` has `--interactive` and `-f`, which
mostly just override each other, because they set the interactive mode and
decide whether to print warnings. However, `--interactive=never` does nog change
decide whether to print warnings. However, `--interactive=never` does not change
whether warnings are printed. Hence, they cannot override completely, because
then these two are **not** identical:

Expand Down Expand Up @@ -59,9 +59,10 @@ Changing these defaults is sometimes just a single line, but other times it
becomes quite verbose. In particular, setting the options to override becomes
quite verbose in some cases.

[^1]: There is a setting to set it for all arguments, but it behaves differently
than setting it individually and leads to some troubles, due to the differences
mentioned in the next section.
[^1]:
There is a setting to set it for all arguments, but it behaves differently
than setting it individually and leads to some troubles, due to the differences
mentioned in the next section.

## Problem 4: Subtle differences

Expand Down Expand Up @@ -111,7 +112,7 @@ uutils diverge.

`clap`'s arguments are identified by strings. This leads to code like this:

```rust
```rust,ignore
const OPT_NAME: &'static str = "name";
// -- snip --
Expand Down Expand Up @@ -183,9 +184,10 @@ libraries.
- Does not support a many-to-many relationship.
- [`bpaf`](https://github.com/pacak/bpaf)
- Extremely flexible, even supports `dd`-style.
- A different configuration between short and long options requires a workaround.
- A different configuration between short and long options requires a
workaround.
- A many-to-many relation ship is possible, though not very ergonomic.
- For more information, see: https://github.com/uutils/uutils-args/issues/17
- For more information, see: <https://github.com/uutils/uutils-args/issues/17>
- [`gumdrop`](https://github.com/murarth/gumdrop)
- Does not handle invalid UTF-8.
- Not configurable enough.
Expand Down
Loading

0 comments on commit 5cdae9b

Please sign in to comment.