-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Formatting guidelines #2436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Formatting guidelines #2436
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
# Rust Style Guide | ||
|
||
## Motivation - why use a formatting tool? | ||
|
||
Formatting code is a mostly mechanical task which takes both time and mental | ||
effort. By using an automatic formatting tool, a programmer is relieved of | ||
this task and can concentrate on more important things. | ||
|
||
Furthermore, by sticking to an established style guide (such as this one), | ||
programmers don't need to formulate ad hoc style rules, nor do they need to | ||
debate with other programmers what style rules should be used, saving time, | ||
communication overhead, and mental energy. | ||
|
||
Humans comprehend information through pattern matching. By ensuring that all | ||
Rust code has similar formatting, less mental effort is required to comprehend a | ||
new project, lowering the barrier to entry for new developers. | ||
|
||
Thus, there are productivity benefits to using a formatting tool (such as | ||
rustfmt), and even larger benefits by using a community-consistent formatting, | ||
typically by using a formatting tool's default settings. | ||
|
||
|
||
## Formatting conventions | ||
|
||
### Indentation and line width | ||
|
||
* Use spaces, not tabs. | ||
* Each level of indentation must be four spaces (that is, all indentation | ||
outside of string literals and comments must be a multiple of four). | ||
* The maximum width for a line is 100 characters. | ||
* A tool should be configurable for all three of these variables. | ||
|
||
|
||
### Blank lines | ||
|
||
Separate items and statements by either zero or one blank lines (i.e., one or | ||
two newlines). E.g, | ||
|
||
```rust | ||
fn foo() { | ||
let x = ...; | ||
|
||
let y = ...; | ||
let z = ...; | ||
} | ||
|
||
fn bar() {} | ||
fn baz() {} | ||
``` | ||
|
||
Formatting tools should make the bounds on blank lines configurable: there | ||
should be separate minimum and maximum numbers of newlines between both | ||
statements and (top-level) items (i.e., four options). As described above, the | ||
defaults for both statements and items should be minimum: 1, maximum: 2. | ||
|
||
|
||
### [Module-level items](items.md) | ||
### [Statements](statements.md) | ||
### [Expressions](expressions.md) | ||
### [Types](types.md) | ||
|
||
|
||
### Comments | ||
|
||
The following guidelines for comments are recommendations only, a mechanical | ||
formatter might skip formatting of comments. | ||
|
||
Prefer line comments (`//`) to block comments (`/* ... */`). | ||
|
||
When using line comments there should be a single space after the opening sigil. | ||
|
||
When using single-line block comments there should be a single space after the | ||
opening sigil and before the closing sigil. Multi-line block comments should | ||
have a newline after the opening sigil and before the closing sigil. | ||
|
||
Prefer to put a comment on its own line. Where a comment follows code, there | ||
should be a single space before it. Where a block comment is inline, there | ||
should be surrounding whitespace as if it were an identifier or keyword. There | ||
should be no trailing whitespace after a comment or at the end of any line in a | ||
multi-line comment. Examples: | ||
|
||
```rust | ||
// A comment on an item. | ||
struct Foo { ... } | ||
|
||
fn foo() {} // A comment after an item. | ||
|
||
pub fn foo(/* a comment before an argument */ x: T) {...} | ||
``` | ||
|
||
Comments should usually be complete sentences. Start with a capital letter, end | ||
with a period (`.`). An inline block comment may be treated as a note without | ||
punctuation. | ||
|
||
Source lines which are entirely a comment should be limited to 80 characters | ||
in length (including comment sigils, but excluding indentation) or the maximum | ||
width of the line (including comment sigils and indentation), whichever is | ||
smaller: | ||
|
||
```rust | ||
// This comment goes up to the ................................. 80 char margin. | ||
|
||
{ | ||
// This comment is .............................................. 80 chars wide. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see the rationale, but this suggestion seems very hard to enforce, esp. in combination with "a mechanical formatter should not change comments except to move them within a file". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe the comment means "a mechanical formatter should not change comments except to move them within a line"? |
||
} | ||
|
||
{ | ||
{ | ||
{ | ||
{ | ||
{ | ||
{ | ||
// This comment is limited by the ......................... 100 char margin. | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Doc comments | ||
|
||
Prefer line comments (`///`) to block comments (`//* ... */`). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how "prefer" can fit with "required for official Rust projects". Is it a violation of the rules if someone writes a doc-comment with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is phrasing to straddle the difference between what the Rust project requires, and what we think should be imposed on other comments. Inside the compiler/stdlib, and as far as I know, in all official projects, we require In other words, it's |
||
|
||
Prefer outer doc comments (`///` or `//*`), only use inner doc comments (`//!` | ||
and `//*!`) to write module-level or crate-level documentation. | ||
|
||
Doc comments should come before attributes. | ||
|
||
### Attributes | ||
|
||
Put each attribute on its own line, indented to the level of the item. | ||
In the case of inner attributes (`#!`), indent it to the level of the inside of | ||
the item. Prefer outer attributes, where possible. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are too many "indentations" in this paragraph, imo. |
||
For attributes with argument lists, format like functions. | ||
|
||
```rust | ||
#[repr(C)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any guidance on attribute ordering? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. The order of attributes can be significant so a tool should never re-order them. I think asking humans to reorder them is too big a thing to be practical. |
||
#[foo(foo, bar)] | ||
struct CRepr { | ||
#![repr(C)] | ||
x: f32, | ||
y: f32, | ||
} | ||
``` | ||
|
||
For attributes with an equal sign, there should be a single space before and | ||
after the `=`, e.g., `#[foo = 42]`. | ||
|
||
There must only be a single `derive` attribute. Note for tool authors: if | ||
combining multiple `derive` attributes into a single attribute, the ordering of | ||
the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)] | ||
struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`. | ||
|
||
### *small* items | ||
|
||
In many places in this guide we specify that a formatter may format an item | ||
differently if it is *small*, for example struct literals: | ||
|
||
```rust | ||
// Normal formatting | ||
Foo { | ||
f1: an_expression, | ||
f2: another_expression(), | ||
} | ||
|
||
// *small* formatting | ||
Foo { f1, f2 } | ||
``` | ||
|
||
We leave it to individual tools to decide on exactly what *small* means. In | ||
particular, tools are free to use different definitions in different | ||
circumstances. | ||
|
||
Some suitable heuristics are the size of the item (in characters) or the | ||
complexity of an item (for example, that all components must be simple names, | ||
not more complex sub-expressions). For more discussion on suitable heuristics, | ||
see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47). | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps remove the second "discussion" in this sentence? For more discussion on suitable heuristics, see this issue. |
||
Tools should give the user an option to ignore such heuristics and always use | ||
the normal formatting. | ||
|
||
|
||
## [Non-formatting conventions](advice.md) | ||
|
||
## [Cargo.toml conventions](cargo.md) | ||
|
||
## [Principles used for deciding these guidelines](principles.md) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Other style advice | ||
|
||
## Expressions | ||
|
||
Prefer to use Rust's expression oriented nature where possible; | ||
|
||
```rust | ||
// use | ||
let x = if y { 1 } else { 0 }; | ||
// not | ||
let x; | ||
if y { | ||
x = 1; | ||
} else { | ||
x = 0; | ||
} | ||
``` | ||
|
||
## Names | ||
|
||
* Types shall be `UpperCamelCase`, | ||
* Enum variants shall be `UpperCamelCase`, | ||
* Struct fields shall be `snake_case`, | ||
* Function and method names shall be `snake_case`, | ||
* Local variables shall be `snake_case`, | ||
* Macro names shall be `snake_case`, | ||
* Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`. | ||
* When a name is forbidden because it is a reserved word (e.g., `crate`), use a | ||
trailing underscore to make the name legal (e.g., `crate_`), or use raw | ||
identifiers if possible. | ||
|
||
### Modules | ||
|
||
Avoid `#[path]` annotations where possible. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# Cargo.toml conventions | ||
|
||
## Formatting conventions | ||
|
||
Use the same line width and indentation as Rust code. | ||
|
||
Put a blank line between the last key-value pair in a section and the header of | ||
the next section. Do not place a blank line between section headers and the | ||
key-value pairs in that section, or between key-value pairs in a section. | ||
|
||
Sort key names alphabetically within each section, with the exception of the | ||
`[package]` section. Put the `[package]` section at the top of the file; put | ||
the `name` and `version` keys in that order at the top of that section, | ||
followed by the remaining keys other than `description` in alphabetical order, | ||
followed by the `description` at the end of that section. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An example would go a long way here, to prevent any ambiguity. |
||
Don't use quotes around any standard key names; use bare keys. Only use quoted | ||
keys for non-standard keys whose names require them, and avoid introducing such | ||
key names when possible. See the [TOML | ||
specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table) | ||
for details. | ||
|
||
Put a single space both before and after the `=` between a key and value. Do | ||
not indent any key names; start all key names at the start of a line. | ||
|
||
Use multi-line strings (rather than newline escape sequences) for any string | ||
values that include multiple lines, such as the crate description. | ||
|
||
For array values, such as a list of authors, put the entire list on the same | ||
line as the key, if it fits. Otherwise, use block indentation: put a newline | ||
after the opening square bracket, indent each item by one indentation level, | ||
put a comma after each item (including the last), and put the closing square | ||
bracket at the start of a line by itself after the last item. | ||
|
||
```rust | ||
authors = [ | ||
"A Uthor <[email protected]>", | ||
"Another Author <[email protected]>", | ||
] | ||
``` | ||
|
||
For table values, such as a crate dependency with a path, write the entire | ||
table using curly braces and commas on the same line as the key if it fits. If | ||
the entire table does not fit on the same line as the key, separate it out into | ||
a separate section with key-value pairs: | ||
|
||
```toml | ||
[dependencies] | ||
crate1 = { path = "crate1", version = "1.2.3" } | ||
|
||
[dependencies.extremely_long_crate_name_goes_here] | ||
path = "extremely_long_path_name_goes_right_here" | ||
version = "4.5.6" | ||
``` | ||
|
||
## Metadata conventions | ||
|
||
The authors list should consist of strings that each contain an author name | ||
followed by an email address in angle brackets: `Full Name <email@address>`. | ||
It should not contain bare email addresses, or names without email addresses. | ||
(The authors list may also include a mailing list address without an associated | ||
name.) | ||
|
||
The license field must contain a valid [SPDX | ||
expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60), | ||
using valid [SPDX license names](https://spdx.org/licenses/). (As an exception, | ||
by widespread convention, the license field may use `/` in place of ` OR `; for | ||
example, `MIT/Apache-2.0`.) | ||
|
||
The homepage field, if present, must consist of a single URL, including the | ||
scheme (e.g. `https://example.org/`, not just `example.org`.) | ||
|
||
Within the description field, wrap text at 80 columns. Don't start the | ||
description field with the name of the crate (e.g. "cratename is a ..."); just | ||
describe the crate itself. If providing a multi-sentence description, the first | ||
sentence should go on a line by itself and summarize the crate, like the | ||
subject of an email or commit message; subsequent sentences can then describe | ||
the crate in more detail. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the rationale behind this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed; this is awkward to check as a human. (I have a gutter at 80 & 100 in sublime when writing rust, but that doesn't help me check the length of a single comment line.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rationale I've seen for this is that paragraph-style text is easier to read with shorter (i.e. 80-char) lines. It is harder to check, but it's also not a huge deal to a) run rustfmt and b) keep approximately within existing comment widths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My interpretation of "a mechanical formatter should not change comments except to move them within a file" is that rustfmt should not do any kind of comment wrapping, which is what would be required for it to fix up too-long or too-short comment lines.
So it's up to the programmer (and their text editor) to get this right. In vim I regularly use the 'gq' command which reflows lines or even entire paragraphs to fit within the current right margin, which is very useful. But this assumes the right margin is constant; if vim has a way of handling a context-sensitive right margin I don't know about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it best practice to have comments be shorter in width than code? In the "Indentation and line width" section above, there is this: The maximum width for a line is 100 characters.
Seems strange to enforce two different width params.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The standard library follows this convention, incidentally. Or at least, comments are wrapped to 80, I'm actually not 100% sure about code.