You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
-1Lines changed: 0 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,6 @@ git clone https://github.com/sunshowers-code/rust-cli-recommendations --branch g
20
20
21
21
then pointing your web browser at `rust-cli-recommendations/index.html`.
22
22
23
-
24
23
Pull requests to fix typos or unclear language are welcome! If you have a suggestion for a change to the document, please [search through the issues] to see if it's been discussed already. If not, please [open an issue].
25
24
26
25
[search through the issues]: https://github.com/sunshowers-code/rust-cli-recommendations/issues?q=is%3Aissue+sort%3Aupdated-desc
Copy file name to clipboardExpand all lines: src/binaries-vs-libraries.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,10 +3,12 @@
3
3
You *may* expose your application's functionality as a library. Some binaries are simple and don't necessarily need to expose their functionality as a library. Other binaries are more complex, in which case their functionality can be exposed as a library that others can build upon.
4
4
5
5
**Why separate libraries from binaries?**
6
+
6
7
* For other consumers of the library, clap and other binary-only dependencies are unnecessary.
7
8
* The binary's versioning is separated out from the library's versioning; see [Versioning](versioning.html) for more.
8
9
9
10
**Reasons against exposing a library**
11
+
10
12
* Maintaining a library in addition to a binary is hard work. It involves documentation and versioning.
11
13
* In some cases, maintainers can decide to expose their functionality *only* as a binary to force a looser coupling with downstream consumers.
12
14
**Case study:* The presence of the [libgit2](https://libgit2.org/) and [JGit](https://www.eclipse.org/jgit/) libraries for Git has made it significantly harder to improve Git's data structures. These libraries are tightly coupled to their consumers, which in practice means that Git improvements are tied to the release schedules of commercial projects like Xcode and Visual Studio.
@@ -17,14 +19,17 @@ You *may* expose your application's functionality as a library. Some binaries ar
17
19
> Note: In this section, "package" means all code scoped to a single `Cargo.toml` file.
18
20
19
21
If your code is meant to be uploaded to a registry like crates.io:
22
+
20
23
* Binary packages *must not* expose their library functionality within the same package.
21
24
* The library package *must* be separated out, with an appropriate name linking the two.
22
25
23
26
If your code is internal to the workspace:
27
+
24
28
* Binary packages *should not* expose a library within the same package.
25
29
* The library package *should* be separated out, with an appropriate name linking the two.
26
30
27
31
Some examples of linked names:
32
+
28
33
**my-lib* for the library, and *my-lib-cli* for the binary, if most people are going to use the library.
29
34
**my-app-core* for the library, and *my-app* for the binary, if most people are going to use the binary.
30
35
**my-utility* for the library, and *cargo-my-utility* for the binary, if your program is a Cargo plugin.
Copy file name to clipboardExpand all lines: src/cli-parser.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,14 @@ When you're writing a Rust command-line application, one of the first things you
4
4
There are a number of different command-line parsers for Rust programs. However, projects *should* use [**clap**](https://crates.io/crates/clap).
5
5
6
6
**Why?**
7
+
7
8
* clap is actively maintained: as of January 2022, clap just came out with a [v3 release]().
8
9
* clap is the most popular command-line parsing library for Rust, which means that there's an existing ecosystem of projects around clap.
9
10
* clap comes with a number of extra features, such as suggestions based on [Jaro–Winkler distance](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance) and full configurability of [commands](https://docs.rs/clap/latest/clap/enum.AppSettings.html) and [arguments](https://docs.rs/clap/latest/clap/enum.ArgSettings.html).
10
11
* There are a number of standard conventions for Unix CLIs: see [this comment](https://github.com/google/argh/issues/3#issuecomment-581144181) by [Stephen Sokolow](https://github.com/ssokolow). clap supports all of them. Another actively maintained project, [argh](https://github.com/google/argh), does not target Unix platforms and so does not support all of these conventions.
11
12
12
13
**Reasons against using clap**
14
+
13
15
* clap pulls in several dependencies and takes quite a while to build.
14
16
* clap increases binary size significantly.
15
17
* clap is a complex parser with many different options. I've found uses for most of them, but they can be overwhelming.
@@ -32,10 +34,12 @@ The doc comments are processed as help text by clap. Here's what the help text l
32
34
```
33
35
34
36
**Why?**
37
+
35
38
* Derive-style arguments are significantly easier to read, write, and modify.
36
39
* Derive-style components can be written once, and reused across multiple commands.
37
40
38
41
**Why not?**
42
+
39
43
* The derive macro is an optional feature that pulls in extra dependencies and increases build times.
40
44
* The derive macro can be a bit magical. Looking at [the source code of clap_derive](https://github.com/clap-rs/clap/blob/master/clap_derive/src/lib.rs), or the generated output with [cargo-expand](https://crates.io/crates/cargo-expand), may be useful.
41
45
* The derive macro is less flexible than the builder API. For example, for an argument used multiple times like `-v -v -v`, the builder API can tell you exactly which position each `-v` was used in. The derive macro can only tell you how many times `-v` was used.
@@ -45,6 +49,7 @@ The doc comments are processed as help text by clap. Here's what the help text l
45
49
## Command and argument case
46
50
47
51
Following Unix and GNU conventions, all commands and arguments, except for short arguments, *must* be in [kebab case](https://en.wikipedia.org/wiki/Kebab_case). This means that:
52
+
48
53
* Commands and arguments *must* be in lowercase.
49
54
* Multiple words *must* be separated by hyphens: `--example-opt`, not `--example_opt` or `--exampleOpt`.
Copy file name to clipboardExpand all lines: src/colors.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,11 +20,13 @@ These rules apply to all command-line programs, not just Rust ones.
20
20
## Color palettes
21
21
22
22
Terminals may support one of three color palettes:
23
+
23
24
**16 colors:* 4-bit color; black, red, green, yellow, blue, magenta, cyan, white, and a "bright" version of each.
24
25
**256 colors:* 8-bit color; the 16 colors above, a 6×6×6 cube for each of red, green and blue, and 24 grayscale tones. [This page by Pádraig Brady](http://www.pixelbeat.org/docs/terminal_colours/#256) has more information about them.
25
26
**Truecolor (16 million colors):* 24-bit color; 8 bits for each of red, green and blue. This is the standard that web pages and most monitors support. You may have seen these colors written as e.g. <spanstyle="color:#9b4fd1">#9b4fd1</span>.
26
27
27
28
**The default color schemes in applications *must* be restricted to 12 colors: red, green, yellow, blue, magenta, cyan, and the bright versions of each of these.**
29
+
28
30
* While the wider palettes are useful for terminal theming controlled by the user, applications *must not* use them by default. The reason is that users may be using a variety of terminal themes with different backgrounds. **Truecolors and 8-bit colors will not render properly with all terminal themes.** Light-colored text will fade into a light background, and dark-colored text will fade into a dark background.
29
31
* Most terminals allow you to configure these colors to whatever one pleases. In most themes, these 12 colors are set to contrast with the background.
30
32
<tt><spanstyle="color: #acacab; background-color:#050505">Themes with dark backgrounds <spanstyle="color: #a9cdeb">set "blue" to be lighter</span></span></tt>,
Copy file name to clipboardExpand all lines: src/configuration.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,7 @@ Some utilities require more expressive power in their configuration; for example
13
13
## Configuration scopes
14
14
15
15
Depending on the application, the following scopes for a configuration are often seen in practice:
16
+
16
17
1.*Directory-scoped.* Applies to a directory and its subdirectories. Controlled by a file somewhere in this directory or a parent. For example, [`.gitignore`](https://git-scm.com/docs/gitignore) is directory-scoped.
17
18
2.*Repository-scoped.* Applies to a repository: controlled by a file somewhere in a code repository. For example, [`clippy.toml`](https://github.com/rust-lang/rust-clippy#configuration) is repository-scoped.
18
19
3.*User-scoped.* A file somewhere in the user's home directory.
@@ -21,16 +22,19 @@ Depending on the application, the following scopes for a configuration are often
21
22
Not all applications support all of these: which scopes make sense is a matter of judgment and thinking about use cases. Some server-side applications support fetching configuration from a remote server; they are out of scope here.
22
23
23
24
**If applications support repository-scoped configuration:**
25
+
24
26
* Applications *should* put repository-scoped configuration in a `.config` directory under the repository root. Typically, applications place their configuration at the top level of the repository. However, too many config files at the top level can pollute directory listings.
25
27
* Applications *should* allow both local and checked-in configuration files. For example, an application `myapp` should support configuration in both `.config/myapp.toml` and `.config/myapp.local.toml`. Entries in `./config/myapp.local.toml`*must* override those in `.config/myapp.toml`.
26
28
27
29
**If applications support user-scoped configuration:**
30
+
28
31
* On Unix platforms other than macOS, applications *should* follow the [XDG specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
29
32
* On macOS and Windows, applications *should* either use `$HOME/.config` or the platform-native config directory. On macOS and Windows, the platform-native directories are somewhat harder to access on the command line, so `$HOME/.config` is a suitable alternative.
30
33
31
34
[dirs](https://crates.io/crates/dirs) is the most actively maintained Rust library for getting the native config directory (and other directories) for every platform.
32
35
33
36
**Applications *may* read configuration options over the command line and the environment.** It is often reasonable to let users override configuration via command-line options and environment variables. If so, then:
37
+
34
38
* Environment variables *must* be prefixed with a unique identifier based on the app. For example, an app called `myapp` can support a "limit" configuration through a `MYAPP_LIMIT` variable.
35
39
* Environment variables *should* also be supported as command-line options. For example, `myapp --limit`. Command-line options are more discoverable than environment variables. If you actually *want* your options to be less discoverable, for example if exposing them would increase support load, you can add hidden command-line options.
36
40
* Command-line arguments *must* override environment variables. An environment variable can be set further up in the environment. A command-line argument expresses user intent most directly.
Copy file name to clipboardExpand all lines: src/handling-arguments.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,7 @@ For a program that has subcommands, the following code structure is *recommended
7
7
```
8
8
9
9
Notes:
10
+
10
11
***Only the top-level `App` is public.**
11
12
***`App` is a struct, one level above the command enum.**
12
13
* While it is possible to make `App` an enum with all the subcommands, in my experience this design has always come back to bite me. This has always been because I've wanted to introduce global options later.
0 commit comments