Fmt-rfcs - RFCs for Rust formatting guidelines and changes to Rustfmt

Overview

Rust code formatting RFCs

This repository exists to decide on a code style for Rust code, to be enforced by the Rustfmt tool. Accepted RFCs live in the text directory and form a specification for formatting tools.

The Rust style guide in this repository documents this style, including examples.

The formatting RFC process

See RFC 1607 for more details. Where this process is under-specified, see the process for Rust RFCs.

  • Open a GitHub issue on the fmt-rfcs repo for discussion. This discussion should define the style in as much detail as possible using rules and examples.
    • Search for existing issues and RFCs that may have already covered the topic. To discourage endless bikeshedding, the style team will close new discussions on old topics unless they provide fresh information (such as feedback based on having an implementation) or alternatives that were not previously considered.
  • When discussion has reached a fixed point, the issue will be put into a final comment period (FCP).
  • Reach consensus on the issue.
  • Implement the style in rustfmt (behind an option if it is not the current default).
  • Submit a PR to fmt-rfcs updating the style guide with the new style and the examples using the newly updated Rustfmt. The PR should include the default values for options to enforce the guideline, and which non-default options should be kept.
  • If discussion is brief and the PR closely matches the original issue, it will be merged. If there are changes, then we will have an FCP for the PR too.
  • Implementation in Rustfmt can then be finished (including any changes due to discussion of the PR), and default options are set.

Scope of the process

This process is specifically limited to formatting style guidelines which can be enforced by Rustfmt with its current architecture. Guidelines that cannot be enforced by Rustfmt without a large amount of work are out of scope, even if they only pertain to formatting.

FCP

FCP will last for approximately two weeks and will be announced in This Week in Rust.

Decision and post-decision process

The style team will make the ultimate decision on accepting or closing a style issue. Decisions should be by consensus. Most discussion should take place on the issue comment thread, a decision should ideally be made when consensus is reached on the thread. Any additional discussion amongst the style team will be summarised on the thread.

Guiding principles

When deciding on style guidelines, discussion should be steered by the following principles (in priority order):

  • readability

    • scan-ability
    • avoiding misleading formatting
    • accessibility - readable and editable by users using the the widest variety of hardware, including non-visual accessibility interfaces
    • readability of code when quoted in rustc error messages
  • aesthetics

    • sense of 'beauty'
    • consistent with other languages/tools
  • specifics

    • compatibility with version control practices - preserving diffs, merge-friendliness, etc.
    • preventing right-ward drift
    • minimising vertical space
  • application

    • ease of manual application
    • ease of implementation (in Rustfmt, and in other tools/editors/code generators)
    • internal consistency
    • simplicity of formatting rules

To see how these principles were decided, see issue 4.

Comments
  • Line and indent width

    Line and indent width

    Decide on the options and defaults for the maximum width of lines and indents.

    Rustfmt currently has the following options:

        max_width: usize, 100, "Maximum width of each line";
        ideal_width: usize, 80, "Ideal width of each line";
        tab_spaces: usize, 4, "Number of spaces per tab";
        hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
    

    The style guide specifies a maximum line width of 99 chars and 4 spaces (no tabs) for indentation. make tidy enforces 100 char width for the Rust repo.

    Mostly these defaults seem reasonable. Points to discuss:

    • 99 or 100 char width,
    • 'ideal width' concept,
    • which options should remain,
    • names of options.

    Notes:

    • ideal width is not really used by rustfmt any more, in retrospect it was a bad idea. The only place it is used (I think) is for comments. I do think wrapping comments at 80 chars is nice, since reading prose is easier in narrower columns and the solid text of large comment blocks looks bad. It might be nice to keep the comment width at 80 and either remove the option to change it, or rename the option.
    • the 99 chars thing is to cope with diffs in 100 chars or newlines in terminals.
    has-PR 
    opened by nrc 128
  • Alignment versus non-aligning indentation

    Alignment versus non-aligning indentation

    For a variety of cases, we should decide between alignment or non-aligning indentation. When breaking a line, should the item on the next line align with the item, or just have an additional level of indentation compared to the previous line? For instance:

    fn alignment(arg: T,
                 arg2: T2)
    
    fn indentation(
            arg: T,
            arg2: T2)
    
    let aligned = (value1
                 + value2);
    let indented = (
            value1
            + value2);
    let indented2 = (
            value1
            + value2
    );
    
    let structval_aligned = S { field: value,
                                field2: value };
    
    let structval_indented = S {
            field: value,
            field2: value,
    };
    
    function_call_aligned(param1,
                          param2);
    function_call_indented(
        param1,
        param2);
    

    This seems mostly orthogonal to indentation size, line length, and where exactly to break various types of lines.

    I would propose avoiding alignment as a general principle. While alignment can sometimes improve readability, it produces significantly more noise in version control, since changes to one line can ripple outward into spacing changes on many lines. Alignment also tends to more quickly drift to the right edge of the screen, and produces worse results when wrapping lines close to a line-length limit.

    In many cases, breaking the line and indenting before the first item provides the same benefit without the corresponding problem.

    opened by joshtriplett 85
  • Function definitions

    Function definitions

    Part of #25: how should we format and indent function definitions? This includes arguments and their types, generics and their constraints, and the braces; the body of the function then falls under #11. This also interacts with where clauses (#38), which we may want to fold in.

    has-PR 
    opened by joshtriplett 67
  • Disable trailing comma by default

    Disable trailing comma by default

    Introduction and background

    When I ran rustfmt yesterday on some code I was writing, I was once again reminded by the fact that our current defaults are the following:

                 where_trailing_comma <boolean> Default: false
                                      Put a trailing comma on where clauses
                struct_trailing_comma [Always|Never|Vertical] Default: Vertical
                                      If there is a trailing comma on structs
            struct_lit_trailing_comma [Always|Never|Vertical] Default: Vertical
                                      If there is a trailing comma on literal structs
                  enum_trailing_comma <boolean> Default: true
                                      Put a trailing comma on enum declarations
           match_block_trailing_comma <boolean> Default: false
                                      Put a trailing comma after a block based match arm (non-block arms are not affected)
        match_wildcard_trailing_comma <boolean> Default: true
                                      Put a trailing comma after a wildcard arm
    

    I know that some of this is ongoing discussion in https://github.com/rust-lang-nursery/fmt-rfcs/issues/34, since it specifically mentions the trailing comma in some situations:

    The last match arm should have a comma if the body is not a block:

    I want to take the chance before #34 is merged to broaden that discussion a bit more, and try to reach consensus on trailing commas in general. (I know that they are sometimes needed; I consider that a bug and this discussion is more related to the areas where it is syntactically optional, but a common de-facto standard in the Rust community and/or enforced by rustfmt.)

    I don't claim to be unbiased; I have a specific opinion that I am voicing in this RFC. However, what I do claim is to represent the different standpoints in a factual way. If you feel that I am missing or misrepresenting some argument for either position, please write a comment with the missing part and I'll try to adjust the proposal continously.

    Basic presumption

    I hope that (almost) everyone can agree that our current position - to sometimes advocate a trailing comma and sometimes not, as shown above - is not optimal. It feels counterintuitive and also like something you'd have to teach people about ("the style guide recommends it here, but not there, for whatever reason" - not saying that there aren't reasons for the inconsistency, just saying that an inconsistent set of rules in an area is much harder to defend and also harder for people to remember.)

    Arguments used to support the addition of trailing commas

    It's commonly used within the rust community

    This is a fact. Servo uses it, rustc uses it, probably a bunch of other projects as well. The precedent is there, there's not so much to say about that. There are probably a number of people who like this style, otherwise it wouldn't have been started to be used anyway. Moving away from this style would risk discouraging those people from contributing to the community.

    Counter-argument

    • It's not that common outside the Rust community.
    • The current Rust code in existance will hopefully eventually be a very small minority of the cumulative amount of rust code in the years to come. In other words, the vast majority of the rust code eventually written does not yet exist.
    • Once rustfmt is stable enough, we should be able to reformat larger codebases (like servo and rustc) with it anyway.
    • Regarding the "people might like it" part, it's a fact regarding any part of the style guide. The style guide cannot emphasise individual people so much, but should rather focus on the greater good for the community as a whole.

    It makes changing the code easier

    This argument is also factually correct; when adding a new entry to an array, you never have to remember adding a trailing comma. Perhaps more importantly so, when rearranging items in an array you don't have to visually scan the array to find which line now has the missing comma (so you can add it and make the code compile again).

    Counter-argument

    While the argument is factually correct, it's pretty much a matter of what you are used to. Good tooling (i.e. instant feedback on the validity of the code, perhaps powered by rls or simiilar) can make this be more of a moot point. If the editor you are using instantly shows you (or hints at) where the missing comma is, this is less of a point as before. (but of course, not all people can be expected to use a single editor/a RLS-powered editor etc.)

    It produces shorter, less verbose diffs

    This argument is based on the simple fact that if the trailing comma is already present on the last line of an {array|enum|match|etc}, that line will not have to be edited if you add a new element to the {array|enum|match}. In other words, the diff produced when changing the code will only include the relevant line (the new functionality being added), you won't have to touch an adjacent line to make it compile.

    This is a very relevant and factual argument, since it avoids the cognitive load put on the brain when parsing the diff. You can focus on the actual change, and have to think less about the noise.

    Counter-argument

    While this is a a factually correct assertion, @bbatsov (the author of Rubocop, a linter for Ruby), wrote that:

    The defaults will not be changed [to enable trailing commas by default] - using VCS diff limitations to justify a coding convention doesn't make sense

    Of course, here is where facts end and opinions start: I personally agree with Boris, that this is too weak an argument to justify the current position. Others might, and will, say the opposite (that this is such a strong argument that the current position should be retained).

    It breaks git blame

    This is actually a pretty good argument. It will appear as if the person who added the comma was the author of that line even though his/her contribution was only the single character. Can't really say much about this, this is a reasonable, factual argument. (However, it's again letting the limitations of a particular tool mandate the style choices)

    Arguments used to reject the addition of trailing commas

    Opinionated: It looks like a typo

    One of my early encounters with the Rust community was actually because of this; I read some code in the Rust compiler source code which struck me as "looking weird", because of the trailing comma. I have been doing programming for about 20 years, of which 14 years of it has been "for a living". Never during these years have I encountered a community that was advocating trailing commas.

    I'm quite certain I'm not alone with this experience (which the SO links further down in this RFC indicates; people tend to get confused when they read code written like this). In my eyes, the current position definitely is not "mainstream" enough for a language with high ambitions to become a broad competitor to languages like C, C++ and perhaps Java, C# and others as well. If that's really what we're aiming for, we should try to aim for a style that "feels natural" to most people reading code without having seen what the style guide advocates.

    Our language is so great because of the other features it provides (immmutability, the whole borrowing concept, proper concurrency etc) that I think that is what should be sticking out when people read our code: our superiority in these areas. Not that we write code that looks like an array element is missing from the end; that someone has forgotten to finish his sentence. Again, extremely opinionated, but it makes people question the code: is this really what the author intended to write? Is there a bug here, did I just discover an unpleasant surprise?

    It is contrary to the recommended style guide/linter defaults for other programming languages

    A non-comprehensive on some of the findings I could gather:

    • rubocop, a linting tool for Ruby, produces warnings for this syntax with its default config. The issue is discussed more in https://github.com/bbatsov/rubocop/issues/713, https://github.com/bbatsov/rubocop/pull/735 and at length in https://github.com/bbatsov/ruby-style-guide/issues/273. Other style guides like the Thoughtbot one advocates trailing comma, but I'd say the former one is the more popular one (and definitely a more comprehensive guide with much more details about the recommendations).
    • eslint, a linting tool for Javascript, has it disabled by default but with options for enforcing it for various scenarios (multi-line only, always, etc).
    • tslint, a linter for Typescript, seems to take the approach to let you configure it either way, but don't seem to advocate a particular default. (tslint is not a reformatter in that sense, so it can take a more relaxed stance on the matter)
    • The PHP manual says that "[h]aving a trailing comma after the last defined array entry, while unusual, is a valid syntax."
    • It has been said to be common in Python, but I couldn't find a style guide to back this claim.

    Other languages/style guides don't typically disallow it, but it's a common source for people to scratch their heads and wonder "why is this valid C#/Python/etc code?". Take a look at this and this link (Python), this link (C#), this link (Java) etc. It is definitely not a universally accepted style, recommended by a large majority of the style guides for programming languages in general or anything like that.

    To put it bluntly: if we want to keep making people confused, we should keep the current recommendation as it is.

    It is invalid code in some languages/environments:

    • JSON: Valid code

      {
        "foo": "bar",
        "baz": "zot"
      }
      

      Invalid code, parsers will reject this:

      {
        "foo": "bar",
        "baz": "zot",
      }
      

    Opinionated: It's not really intended for humans writing code

    The fact that virtually all programming languages (except from JSON, which isn't really a "programming language") allows it seems to be generally motivated by the fact that it's intended for code generation, where it's obviously a whole lot easier for the code generating code to not have to always check "is this the last element of the array being printed to stdout" and so forth. C# 2005 Programmer's Reference (p. 208) seems to imply this, and this SO thread gives the same impression. It was initially allowed in C back from the days of K&R, and many other languages have included support for it since.

    One could argue that if this "feature" is designed for code generators, let the code generators use it and let humans produce code that is more aesthetically pleasing and straightforward.

    Conclusion and proposed adjustment

    I find the communities for various programming languages a bit scattered on the subject. Some people prefer this style very strongly, others (like me) dislike it equally strongly and would never ever want to run a tool to reformat our code with the default settings as they are right now. Others are just confused by reading code formatted like this and start to ask questions about it. That, to me, indicates that our current defaults are not so intuitive and hence I suggest that the following settings should be the new default:

                 where_trailing_comma <boolean> Default: false
                                      Put a trailing comma on where clauses
                struct_trailing_comma [Always|Never|Vertical] Default: Never
                                      If there is a trailing comma on structs
            struct_lit_trailing_comma [Always|Never|Vertical] Default: Never
                                      If there is a trailing comma on literal structs
                  enum_trailing_comma <boolean> Default: false
                                      Put a trailing comma on enum declarations
           match_block_trailing_comma <boolean> Default: false
                                      Put a trailing comma after a block based match arm (non-block arms are not affected)
        match_wildcard_trailing_comma <boolean> Default: false
                                      Put a trailing comma after a wildcard arm
    

    IMHO, this would be very consistent and easy to understand for anyone: experts and new Rust enthusiasts alike.

    Now, you may send the expected flames... 😉

    has-PR 
    opened by perlun 58
  • Comments

    Comments

    As well as specifying formatting for comments, we should decide on how much we expect Rustfmt to enforce (at the least, it cannot enforce correct grammar). My experience has been that re-formatting comments is almost impossible to get right. However, it is possible that we might be able formulate acceptable heuristics if we want to go down that road.

    This one will need some fleshing out, but to start with:

    • Prefer // comments to /* ... */ comments, use the latter only where there is code following on the same line.
    • Prefer /// for doc comments, use //! only for module/crate-level docs. Avoid the other forms.
    • Comments should be complete sentences. Start with a capital letter, (usually) end with a period (.).
    • Have a single space after the comment sigils: // A comment. or /// A doc comment.
    • Comments should be indented with the code they are 'attached' to.
    • Comments should be kept within the 80 char margin (longer comments are harder to read).

    I do not believe we should get into what makes a comment good or bad, beyond its formatting.

    I propose that Rustfmt should basically avoid formatting comments. It can move comments to make them aligned with code and can add or remove whitespace around comments (if necessary, and I suspect it won't be). But Rustfmt should not change the actual text of the comment at all. Rustfmt should warn if a comment runs over the maximum width, but shouldn't attempt to fix that. Rustfmt should not change the style of the comment, nor the whitespace inside a comment.

    I'd be happy to have more sophisticated comment formatting (word-wrapping, etc.) behind an option, if that is of interest to users.

    ready-for-PR 
    opened by nrc 45
  • Ordering of types of groups within a module

    Ordering of types of groups within a module

    Is there any guidance about the general order of how things should be defined in a module? For example.

    extern crate ...
    
    use ...
    
    // Declaring modules.
    mod ...
    
    // Rest of code: consts, structs, impl, functions, trait, etc
    

    I'm unclear where mod declarations should go (before use or after use?). I can't find if this has been discussed before. I'm not sure it's something rustfmt would try to fix, but having a guideline could still be helpful. Relates to #24.

    Edit: ~~Sometimes you need to declare a mod before you can import it:~~

    has-PR 
    opened by johnthagen 44
  • Define 'short'

    Define 'short'

    Currently Rustfmt treats certain items differently if they are 'short'. For example, it will but a short struct literal on one line:

    // Short
    let x = Foo { x: 42 };
    
    // Not short
    let opts = Options {
        flag_package: vec![],
        flag_jobs: None,
        flag_features: vec![],
        flag_all_features: false,
        flag_no_default_features: false,
    };
    

    As @joshtriplett points out in https://github.com/rust-lang-nursery/fmt-rfcs/issues/31#issuecomment-268343997, we should have one global definition of 'short' rather than a different definition every time.

    I see two ways to define 'short' - absolute characters (e.g., 25) or proportion of max line length (e.g., 1/4). One might argue that no matter how long the line length, what makes (e.g.) a struct literal readable on one line does not change. On the other hand, people who prefer longer lines might also prefer more on one line in these cases.

    P-high 
    opened by nrc 44
  • Convention about empty lines

    Convention about empty lines

    Hi everybody.

    It looks like there is no any convention about empty lines.

    I like to separate all function with one empty line.

    fn foo() {}
    
    fn bar() {}
    

    I like to separate Control Flow Statements with one empty line.

    fn foo(x: i32) -> i32 {
        let result = calculate(x);
    
        if result > 0 {
            result
        } else {
            0
        }
    }
    

    I like to separate blocks with one empty line.

    fn foo() {
        {
            do_something();
            do_something_else();
        }
    
        {
            do_something_different();
            do_something_completely_different();
        }
    }
    

    I like to separate unrelated pieces with one empty line.

    fn foo() {
        let mut x = create_x();
        x.do();
        x.do_something_else();
    
        let mut y = create_y();
        y.do();
        y.do_something_else();
    }
    

    I think we should have some convention about it.

    Thanks, Alexey

    has-PR 
    opened by KalitaAlexey 42
  • Decide on guiding principles

    Decide on guiding principles

    We should decide on the principles behind the formatting guidelines and their relative priority.

    Some ideas (not in order):

    • internal consistency
    • readability (needs further expansion)
    • scan-ability (ditto)
    • preventing right-ward drift
    • preserving diffs
    • minimising vertical space
    • helpfulness to tools?
    • consistency with formatting used in other languages (either automatic, or defined in style guides)
    • ease of manual formatting
    • ease of automatic formatting for editors not using Rustfmt
    • ease of implementation
    • ease of re-implementation in other formatting tools
    • simplicity of formatting rules
    • aesthetics (boy, does this need further expansion)
    P-high 
    opened by nrc 37
  • match

    match

    basics

    match $discr {
        $arm1
        $arm2
        ...
    }
    

    Spaces and newlines as shown. In particular, prefer not to line-break the discriminant if possible; each match arm must have its own line; arms are block indented.

    simple arms

    Short arm:

    $pat if $expr => $expr,
    

    Prefer the above form if the arm fits on one line.

    Avoid single line blocks:

    $pat if $expr => { $expr }   // No
    

    The last match arm should have a comma if the body is not a block:

    match $expr {
        $expr => foo,
        $expr => bar,
    }
    

    Block body:

    $pat if $expr => {
        ...
    }
    

    Note no comma if using a block, prefer not to line-break pattern or if clause, block indentation of arm body.

    Empty blocks:

    $pat if $expr => {}
    

    Note {} not (), no comma, no space in the block.

    Question - multi-line single expressions

    Should a block be required?

    E.g.,

    match foo {
        bar => 42,
        baz => a_very_long_expr(dsfsdfsdfa,
                                dsafdfa,
                                dsfsfdsfdsfsd),
    }
    
    // vs
    
    match foo {
        bar => 42,
        baz => {
            a_very_long_expr(dsfsdfsdfa,
                             dsafdfa,
                             dsfsfdsfdsfsd)
        }
    }
    

    Rustfmt currently does the latter, I found that it sometimes makes it easier to read, helps prevent rightward drift, and gets around the slightly unfortunate issue of expressions with blocks needing a comma:

    match foo {
        bar => 42,
        baz => if qux {
            ...
        },  // comma needed here :-(
    }
    

    I'm no longer 100% convinced this is worth the extra vertical space however. We might want to leave this question unanswered for a while since the benefit in preventing rightward drift would not be so important if we pick a style which other wise prevents it (e.g., by using two space indent, or using more block indentation):

    match foo {
      bar => 42,
      baz => a_very_long_expr(dsfsdfsdfa,
        dsafdfa,
        dsfsfdsfdsfsd),
    }
    

    Breaking the arm

    Prefer breaking before the body:

    $pat =>
        $expr,
    

    or

    $pat => {
        ...
    }
    

    Then prefer breaking before the if (if present, see below).

    Then prefer breaking the pattern at |s (if there are multiple sub-patterns, see below). If breaking the pattern, the rest of the arm should only be broken as necessary. E.g., the following are ok:

    pat1 |
    pat2 |
    pat3 if $expr => {
        ...
    }
    pat1 |
    pat2 |
    pat3 => $expr,
    pat1 |
    pat2 |
    pat3 if $expr => $expr,
    

    Finally, break each pattern if necessary.

    Breaking before if

    If necessary to break before the if, it should be block indented, a block is required for the arm body, and the { of the block should be on a newline. This helps prevent the if clause be distinguished from the arm body. Never break after the if:

    $pat
        if $expr =>
    {
        ...
    }
    

    If $expr does not fit on one line, break it according to the rules for expressions.

    large patterns

    If using a compound pattern (pat1 | pat2), prefer to put the whole pattern on one line. If it does not fit, put each sub-pattern on a new line, with the line terminated by |:

    pat1 |
    pat2 |
    pat3 => {
        ...
    }
    

    If any sub-pattern does not on the line, break it according to the rules for patterns.

    Question - blank lines between arms

    These are sometimes useful for indicating groups of arms, I propose Rustfmt leaves single blank lines where the user writes them and coalesces multiple blank lines into one. E.g.,

    match $expr {
        $expr => foo,
    
        $expr => bar,
    }
    

    Question - consistency between arms

    Should we allow a mix of block arms and single expression arms? Or should we use blocks for every arm if any arm requires it? The second alternative is more consistent, but wastes some space. It also looks odd in the relatively common case where there is a single large arm and many small arms.

    Question - exhaustiveness

    Should we offer any guidance about using _ in match arms? I feel there are strong idioms for using this or not depending on desired backwards compatibility. However, it may be beyond the remit of the style guide/process.

    ready-for-PR 
    opened by nrc 33
  • Should formatting be customisable? How?

    Should formatting be customisable? How?

    In the short-term, we need ways to experiment with how Rustfmt formats. However, what should the long term look like? There are wins if all code looks the same in terms of adjusting to new projects, and this approach is taken by Gofmt. On the other hand, we can never please everyone with a single formatting style, and people using Rustfmt with different styles is better than people not using Rustfmt at all (and the Rust community is not as 'conformant' as the Go community); this approach is taken by ClangFormat.

    Currently, we have a rustfmt.toml file with many disparate options. If we do decide to keep some customisation, we should at the least decide on a strategy for what kind of options we want to present and how they are organised.

    Finally, we have some options for introducing 'speed bumps' to customisation, we could:

    • only allow customisation on nightly (vs stable or beta), this somewhat follows stabilisation policy for Rust)
    • only allow customisation on Rustfmt build from source, rather than from distributed binaries
    • only allow customisation of rustfmt, but not cargo fmt (I think this one is a terrible idea, but brain-storming...)
    • opt-in to customisation with a command line argument or environment variable
    • rustfmt distributed with Rust (some day, assuming this happens) does not permit customisation, but you can download a separate version which does.
    • sure there are others

    The idea with these speed bumps is we more strongly encourage users to use the default formatting, but permit customisation where it is necessary (e.g., corporate pressure, interaction with existing codebases, bloody-mindedness)

    P-high has-PR 
    opened by nrc 32
  • Allow chains to condense to remove some single line `)`

    Allow chains to condense to remove some single line `)`

    One common complaint I've seen (and made myself) coming to rust-guide-formatted code from many other languages is the vertical-ness of a lot of common rust code. This leads to less context when viewing diffs (or functions entirely in smaller editor windows) which can be a common source of bugs. There's good reason for the vertical layout in many cases, of course - it can substantially improve scan-ability of code layout, and like all things, there is a balance to be had.

    One common pattern in Rust is a somewhat long line causing a closing ) to be on its own line. While this can improve scan-ability, it can generate some very awkward looking chains, especially with a trailing unwrap(), which is also exceedingly common.

    For example, we have some code which is formatted as

            let data = Vec::<u8>::from_hex(
                "02020202020202020202 longish hex constant",
            )
            .unwrap();
    

    according to https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/expressions.md#multi-line-elements

    At the risk of starting a long discussion and flame-war on the topic of chains, I don't believe scan-ability of the code is substantially impacted (or arguably positively impacted by a change to allow the unwrap to appear on the same line as the ), as follows:

            let data = Vec::<u8>::from_hex(
                "02020202020202020202 longish hex constant",
            ).unwrap();
    

    As a general principle, though its totally reasonable to have it be of the lowest priority, having a "provide more context in diffs and during editing by making things single-line where it does not at all impact scan-ability" principle would serve to avoid some bugs which, in my experience, are not entirely uncommon, though arguably scan-ability can sometimes avoid more/other bugs.

    opened by TheBlueMatt 0
  • Wrapping rules for let-chains?

    Wrapping rules for let-chains?

    Feature tracking issue: rust-lang/rust#53667

    Should we introduce a new guideline for wrapping let-chains?

    The rationale is that let-chains allow let bindings to be anywhere in a line of code. let is no longer consitently at the left side. It is good for let bindings to stand out and be easy to discover since they introduce new variables for the following scope. Oftentimes when reading code, I look backwards with the question "where did this variable come from?"

    Possible answers

    1. No change. Wrap let expressions the same as any other expression.

    2. Always wrap let expressions. let is only ever preceded by one token in the same line: if, while, &&, ||, etc.

    3. Wrap let expressions if they begin N characters or more past the current indentation.

      For example, a let-expression may be on the same line if it is 15 characters from the left margin. If it is 16 characters from the left margin, it must break to the next line.

    4. Wrap let expressions if there are 2 (?) or more let expressions in the condition

    5. Allow single_identifier && let on one line (if it fits line length limits), but require a line break before the && for any other expression. Always wrap after a let expression.

    Potential concerns for each answer

    1. The introduction of x may be hard to find in this case:
      if my_long_condition(foo, bar, baz) && some_more && let Some(x) = foo() {
          // lots of code...
          use_x(x);
      
    2. Wrapping for this case seems a little unnecessary since it only shifts let leftward by one character:
      if a
          && let Some(b) = foo()
      {
      
    3. Added complexity to formatting logic. Difficult to follow/verify the guideline without automated tooling. The subtlety of the logic may be surprising to users.
    4. This case is suboptimal (similar to 1):
      if my_function(Some(get_thing()), variable, and_another) && let Some(x) = foo() {
      

    Other considerations

    The rules for if and while will be the same.

    If a let expression wraps, it will cause all of the && or ||-separated expressions to be on separate lines.

    if something
        && let Some(x) = foo() && something_else { // bad - `&& something_else` should be on its own line
    

    If there is just one let binding at the beginning, the condition may be on one line:

    if let Some(foo) = do_something() && another_condition {
    
    opened by camsteffen 32
  • Clarify muliti-line chain elements

    Clarify muliti-line chain elements

    Say (and show) that a multi-line element causes all surrounding elements to be on their own line, not just later elements. But also maintain the caveat where multiple elements may be on the first line.

    I added a closure the example so that it is more certainly a multi-line element.

    See #151

    opened by camsteffen 1
  • Formatting guidelines for inline assembly

    Formatting guidelines for inline assembly

    An issue I've observed in several contexts discussing the new asm! syntax for inline assembly: everyone formats asm! statements differently, and we should 1) come up with guidance on how to do so, and 2) implement that guidance in rustfmt.

    Notably, this includes how to format both single-line and multi-line assembly statements.

    EDIT: I've updated these guidelines to use the new support for multiple template string arguments, implemented in https://github.com/rust-lang/rust/pull/73364 .

    With my style team hat on, I would propose the following guidelines:

    • Single-line assembly code should be formatted as a single string argument and treated as any other argument to a format macro.
    • Multi-line assembly code should be formatted with one string argument per line of assembly, indented as separate arguments:
      asm!(
          "instruction 1",
          "instruction 2",
          ...,
      );
      
    • Common assembly formatting such as \n\t (often seen in inline assembly for other compilers that directly copy the provided string into their assembly output) is not necessary with Rust inline assembly. Focus on keeping the assembly readable. Note that Rust is not prescriptive about the formatting of your assembly, so if you wish to put multiple instructions or directives or labels on one line (and thus within one assembly string), you can do so, and rustfmt will treat each assembly string as a line.
    • Use the opening " of each string as the base for any indentation within the assembly code; for instance, if you want to indent instructions four spaces past labels, include the indentation inside the string before the instructions. That way, Rust formatting can keep the strings aligned and your assembly code will remain aligned within them:
      asm!(
          "1:",
          "    instruction 1",
          "    instruction 2",
          "2:",
          "    instruction 3",
      );
      
    • Simple asm! with only one assembly string can have the entire asm! including all its arguments on the same line, if the whole thing from asm!( to ); (plus indentation) fits in the line width.
    • Any asm! block that needs breaking across multiple lines, or any asm! block that has multiple assembly strings no matter how short, should always put each argument on its own line, aligned one indentation level past the asm!, with a trailing comma on each, just like a function.
    • options(...) goes on one line if it fits; otherwise, format it as though it were a nested function call to a function named options.
    • Never place any space or line breaks inside of in(reg) or out(reg) or inout(reg) or in("regname") or out("regname") or similar; always treat them as a single atomic unit.
    • If an inout or inlateout pair of expressions are too long to fit on one line, break before (never after) the =>, and indent the => one level further:
      asm!(
          "instruction {}",
          inout(reg) very_long_expression
              => very_long_out_expression,
      )
      
    • If an in(reg) or out(reg) or lateout(reg) expression is too long, break between the ) and the expression and indent one level, then format from there; however, if the expression can be broken internally, follow same the rules for when to leave the head of the expression on the same line as the in(reg) or similar as if in(reg) were the opener of a function:
      asm!(
          "instruction {}",
          in(reg)
              extremely_long_unbreakable_expression,
          in(reg) function_name()
              .method_name(method_arg)
              .further_chained_method(),
          out(reg) long_function_name(
              long_function_argument_expression,
          ),
      );
      
    • For named arguments like name = in(reg) expression, line-break it as you would an assignment statement with the same indentation, treating the in(reg) expression as the right-hand side of the assignment, and following all the same rules as above.
    opened by joshtriplett 22
  • Question about first line of multi-line chain

    Question about first line of multi-line chain

    I have a question about Chains of fields and method calls.

    We have this statement

    If formatting on multiple lines, each field access or method call in the chain should be on its own line...

    ...and then two exceptions to that statement (if I understand correctly). The first is for cases where the first element is "too short" and causes the second element to float. Makes sense.

    The second exception is the following:

    Multi-line elements

    If any element in a chain is formatted across multiple lines, then that element and any later elements must be on their own line. Earlier elements may be kept on a single line. E.g.,

    a.b.c()?.d
        .foo(
            an_expr,
            another_expr,
        )
        .bar
        .baz
    

    This seems like an arbitrary exception to the first statement. Why is the first line allowed to have multiple elements and not broken at .d? Or, why not allow the first line of a chain to contain multiple elements for any chain? Perhaps more elements on the first line should be allowed, but not preferred, for any chain.

    I was not able to find rationale for this decision in #66. Sorry if I missed it.

    opened by camsteffen 7
Owner
null
🍅 A command-line tool to get and set values in toml files while preserving comments and formatting

tomato Get, set, and delete values in TOML files while preserving comments and formatting. That's it. That's the feature set. I wrote tomato to satisf

C J Silverio 15 Dec 23, 2022
Cross-platform Rust library for coloring and formatting terminal output

Coloring terminal output Documentation term-painter is a cross-platform (i.e. also non-ANSI terminals) Rust library for coloring and formatting termin

Lukas Kalbertodt 75 Jul 28, 2022
Vari (Väri) is a Rust library for formatting strings with colors and cosmetic stuff to the terminal.

Vari Vari (Väri) is a Rust library for formatting strings with colors and cosmetic stuff to the terminal. Like Rich library for Python. Väri means "co

azur 13 Nov 2, 2022
⚡️Highly efficient data and string formatting library for Rust.

⚡️Highly efficient data and string formatting library for Rust. ?? Overview Pad and format string slices and generic vectors efficiently with minimal

Firelink Data 3 Dec 21, 2023
Monorepo for dprint—a pluggable and configurable code formatting platform

dprint Monorepo for dprint—a pluggable and configurable code formatting platform. This project is under active early development. I recommend you chec

null 1.7k Jan 8, 2023
Sleek is a CLI tool for formatting SQL. It helps you maintain a consistent style across your SQL code, enhancing readability and productivity.

Sleek: SQL Formatter ✨ Sleek is a CLI tool for formatting SQL. It helps you maintain a consistent style across your SQL code, enhancing readability an

Nick Rempel 40 Apr 20, 2023
Fast, minimal, feature-rich, extended formatting syntax for Rust!

Formatting Tools Fast, minimal, feature-rich, extended formatting syntax for Rust! Features include: Arbitrary expressions inside the formatting brace

Casper 58 Dec 26, 2022
Social media style compact number formatting for rust.

prettty-num Format integers into a compact social media style format, similar to using Intl.NumberFormat("en", { notation: "compact" }); as a number f

null 5 Aug 17, 2024
A CLI tool you can pipe code and then ask for changes, add documentation, etc, using the OpenAI API.

AiBro This is your own little coding bro, immersed in the world of AI, crypto, and all other types of over hyped tech trends. You can pipe it code and

Josh Bainbridge 5 Sep 5, 2023
A git command to quickly save your local changes in case of earthquake !

git-eq (aka git earthquake) Earthquakes are part of the daily life in many countries like in Taiwan. git-eq is a simple git command to quickly save yo

Jérôme MEVEL 6 Dec 16, 2022
Helps you keep track of time for team members across different time zones & DST changes

Teamdate Helps you keep track of time for team members across different timezones and other daylight saving changes based off their location. Because

Alex Snaps 7 Jan 9, 2023
A monitor (service) for your monitor (display). Intercepts window behaviour when monitor configuration changes.

Mon-Mon A monitor (service) for your monitor (display). Listens for changes to display configuration (e.g. plugging in an additional screen) and allow

dan 5 Sep 29, 2023
Warp is a blazingly fast, Rust-based terminal that makes you and your team more productive at running, debugging, and deploying code and infrastructure.

Warp is a blazingly fast, Rust-based terminal that makes you and your team more productive at running, debugging, and deploying code and infrastructure.

Warp 10.4k Jan 4, 2023
Sets of libraries and tools to write applications and libraries mixing OCaml and Rust

Sets of libraries and tools to write applications and libraries mixing OCaml and Rust. These libraries will help keeping your types and data structures synchronized, and enable seamless exchange between OCaml and Rust

Meta 36 Jan 28, 2023
A comprehensive collection of resources and learning materials for Rust programming, empowering developers to explore and master the modern, safe, and blazingly fast language.

?? Awesome Rust Lang ⛰️ Project Description : Welcome to the Awesome Rust Lang repository! This is a comprehensive collection of resources for Rust, a

Shubham Raj 16 May 29, 2023
REC2 (Rusty External Command and Control) is client and server tool allowing auditor to execute command from VirusTotal and Mastodon APIs written in Rust. 🦀

Information: REC2 is an old personal project (early 2023) that I didn't continue development on. It's part of a list of projects that helped me to lea

Quentin Texier (g0h4n) 104 Oct 7, 2023
A lightweight and high-performance order-book designed to process level 2 and trades data. Available in Rust and Python

ninjabook A lightweight and high-performance order-book implemented in Rust, designed to process level 2 and trades data. Available in Python and Rust

Ninja Quant 134 Jul 22, 2024
This is a simple lnd poller and web front-end to see and read boosts and boostagrams.

Helipad This package will poll a Lightning LND node for invoices related to Podcasting 2.0 and display them in a web interface. It's intended for use

Podcastindex.org 26 Dec 29, 2022