]> git.lizzy.rs Git - rust.git/blobdiff - README.md
Merge pull request #2303 from topecongiro/issue-2296
[rust.git] / README.md
index 74ed52129a4523406003bf58129906047241003f..6604725ba76cf6d7430cadf0731a4002c3b4a43e 100644 (file)
--- a/README.md
+++ b/README.md
-# rustfmt
+# rustfmt [![Build Status](https://travis-ci.org/rust-lang-nursery/rustfmt.svg)](https://travis-ci.org/rust-lang-nursery/rustfmt) [![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-lang-nursery/rustfmt?svg=true)](https://ci.appveyor.com/project/nrc/rustfmt) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly)
 
 A tool for formatting Rust code according to style guidelines.
 
+If you'd like to help out (and you should, it's a fun project!), see
+[Contributing.md](Contributing.md).
 
-## How to use
+We are changing the default style used by rustfmt. There is an ongoing [RFC
+process][fmt rfcs]. The last version using the old style was 0.8.6. From 0.9
+onwards, the RFC style is the default. If you want the old style back, you can
+use [legacy-rustfmt.toml](legacy-rustfmt.toml) as your rustfmt.toml.
 
-`cargo build` to build.
+The current `master` branch uses libsyntax (part of the compiler). It is
+published as `rustfmt-nightly`. The `syntex` branch uses Syntex instead of
+libsyntax, it is published (for now) as `rustfmt`. Most development happens on
+the `master` branch, however, this only supports nightly toolchains. If you use
+stable or beta Rust toolchains, you must use the Syntex version (which is likely
+to be a bit out of date). Version 0.1 of rustfmt-nightly is forked from version
+0.9 of the syntex branch.
 
-`cargo test` to run all tests.
 
-`cargo run filename` to run on a file, if the file includes out of line modules,
-then we reformat those too. So to run on a whole module or crate, you just need
-to run on the top file. You'll probably want to set the `WriteMode` in the call
-to `run` in `main()`. Eventually you should be able to set the mode from the
-command line or from a config file or something.
+## Quick start
+
+You must be using the latest nightly compiler toolchain.
+
+To install:
+
+```
+cargo install rustfmt-nightly
+```
+
+to run on a cargo project in the current working directory:
+
+```
+cargo fmt
+```
+
+## Installation
+
+```
+cargo install rustfmt-nightly
+```
+
+or if you're using [Rustup](https://www.rustup.rs/)
+
+```
+rustup update
+rustup run nightly cargo install rustfmt-nightly
+```
 
-You'll need a pretty up to date version of the nightly version of Rust.
+If you don't have a nightly toolchain, you can add it using rustup:
 
-## Use cases
+```
+rustup install nightly
+```
 
-A formatting tool can be used in different ways and the different use cases can
-affect the design of the tool. The use cases I'm particularly concerned with are:
+You can make the nightly toolchain the default by running:
 
-* running on a whole repo before check-in
-  - in particular, to replace the `make tidy` pass on the Rust distro
-* running on code from another project that you are adding to your own
-* using for mass changes in code style over a project
+```
+rustup default nightly
+```
 
-Some valid use cases for a formatting tool which I am explicitly not trying to
-address (although it would be nice, if possible):
+If you choose not to do that you'll have to run rustfmt using `rustup run ...`
+or by adding `+nightly` to the cargo invocation.
 
-* running 'as you type' in an IDE
-* running on arbitrary snippets of code
-* running on Rust-like code, specifically code which doesn't parse
-* use as a pretty printer inside the compiler
-* refactoring
-* formatting totally unformatted source code
+Usually cargo-fmt, which enables usage of Cargo subcommand `cargo fmt`, is
+installed alongside rustfmt. To only install rustfmt run
 
+```
+cargo install --no-default-features rustfmt-nightly
+```
+## Installing from source
 
-## Scope and vision
+To install from source, first checkout to the tag or branch you want to install, then issue
+```
+cargo install --path  .
+```
 
-I do not subscribe to the notion that a formatting tool should only change
-whitespace. I believe that we should semantics preserving, but not necessarily
-syntax preserving, i.e., we can change the AST of a program.
+This will install `rustfmt` in your `~/.cargo/bin`. Make sure to add `~/.cargo/bin` directory to
+your PATH variable.
 
-I.e., we might change glob imports to list or single imports, re-order imports,
-move bounds to where clauses, combine multiple impls into a single impl, etc.
 
-However, we will not change the names of variables or make any changes which
-*could* change the semantics. To be ever so slightly formal, we might imagine
-a compilers high level intermediate representation, we should strive to only
-make changes which do not change the HIR, even if they do change the AST.
+## Running
 
-I would like to be able to output refactoring scripts for making deeper changes
-though. (E.g., renaming variables to satisfy our style guidelines).
+You can run Rustfmt by just typing `rustfmt filename` if you used `cargo
+install`. This runs rustfmt on the given file, if the file includes out of line
+modules, then we reformat those too. So to run on a whole module or crate, you
+just need to run on the root file (usually mod.rs or lib.rs). Rustfmt can also
+read data from stdin. Alternatively, you can use `cargo fmt` to format all
+binary and library targets of your crate.
 
-My long term goal is that all style lints can be moved from the compiler to
-rustfmt and, as well as warning, can either fix problems or emit refactoring
-scripts to do so.
+You'll probably want to specify the write mode. Currently, there are modes for
+`diff`, `replace`, `overwrite`, `display`, `coverage`, `checkstyle`, and `plain`.
 
-### Configurability
+* `overwrite` Is the default and overwrites the original files _without_ creating backups.
+* `replace` Overwrites the original files after creating backups of the files.
+* `display` Will print the formatted files to stdout.
+* `plain` Also writes to stdout, but with no metadata.
+* `diff` Will print a diff between the original files and formatted files to stdout.
+         Will also exit with an error code if there are any differences.
+* `checkstyle` Will output the lines that need to be corrected as a checkstyle XML file,
+  that can be used by tools like Jenkins.
 
-I believe reformatting should be configurable to some extent. We should read in
-options from a configuration file and reformat accordingly. We should supply at
-least a config file which matches the Rust style guidelines.
+The write mode can be set by passing the `--write-mode` flag on
+the command line. For example `rustfmt --write-mode=display src/filename.rs`
 
-There should be multiple modes for running the tool. As well as simply replacing
-each file, we should be able to show the user a list of the changes we would
-make, or show a list of violations without corrections (the difference being
-that there are multiple ways to satisfy a given set of style guidelines, and we
-should distinguish violations from deviations from our own model).
+`cargo fmt` uses `--write-mode=overwrite` by default.
 
+If you want to restrict reformatting to specific sets of lines, you can
+use the `--file-lines` option. Its argument is a JSON array of objects
+with `file` and `range` properties, where `file` is a file name, and
+`range` is an array representing a range of lines like `[7,13]`. Ranges
+are 1-based and inclusive of both end points. Specifying an empty array
+will result in no files being formatted. For example,
 
-## Implementation philosophy
+```
+rustfmt --file-lines '[
+    {"file":"src/lib.rs","range":[7,13]},
+    {"file":"src/lib.rs","range":[21,29]},
+    {"file":"src/foo.rs","range":[10,11]},
+    {"file":"src/foo.rs","range":[15,15]}]'
+```
 
-Some details of the philosophy behind the implementation.
+would format lines `7-13` and `21-29` of `src/lib.rs`, and lines `10-11`,
+and `15` of `src/foo.rs`. No other files would be formatted, even if they
+are included as out of line modules from `src/lib.rs`.
 
+If `rustfmt` successfully reformatted the code it will exit with `0` exit
+status. Exit status `1` signals some unexpected error, like an unknown option or
+a failure to read a file. Exit status `2` is returned if there are syntax errors
+in the input files. `rustfmt` can't format syntactically invalid code. Finally,
+exit status `3` is returned if there are some issues which can't be resolved
+automatically. For example, if you have a very long comment line `rustfmt`
+doesn't split it. Instead it prints a warning and exits with `3`.
 
-### Operate on the AST
+You can run `rustfmt --help` for more information.
 
-A reformatting tool can be based on either the AST or a token stream (in Rust
-this is actually a stream of token trees, but its not a fundamental difference).
-There are pros and cons to the two approaches. I have chosen to use the AST
-approach. The primary reasons are that it allows us to do more sophisticated
-manipulations, rather than just change whitespace, and it gives us more context
-when making those changes.
 
-The advantage of the tokens approach are that you can operate on non-parsable
-code. I don't care too much about that, it would be nice, but I think being able
-to sophisticated transformations is more important. In the future I hope to
-(optionally) be able to use type information for informing reformatting too. One
-specific case of unparsable code is macros. Using tokens is certainly easier
-here, but I believe it is perfectly solvable with the AST approach. At the limit,
-we can operate on just tokens in the macro case.
+## Running Rustfmt from your editor
 
-I believe that there is not in fact that much difference between the two
-approaches. Due to imperfect span information, under the AST approach, we
-sometimes are reduced to examining tokens or do some re-lexing of our own. Under
-the tokens approach you need to implement your own (much simpler) parser. I
-believe that as the tool gets more sophisticated, you end up doing more at the
-token-level, or having an increasingly sophisticated parser, until at the limit
-you have the same tool.
+* [Vim](https://github.com/rust-lang/rust.vim#formatting-with-rustfmt)
+* [Emacs](https://github.com/rust-lang/rust-mode)
+* [Sublime Text 3](https://packagecontrol.io/packages/RustFmt)
+* [Atom](atom.md)
+* Visual Studio Code using [vscode-rust](https://github.com/editor-rs/vscode-rust), [vsc-rustfmt](https://github.com/Connorcpu/vsc-rustfmt) or [rls_vscode](https://github.com/jonathandturner/rls_vscode) through RLS.
 
-However, I believe starting from the AST gets you more quickly to a usable and
-useful tool.
+## Checking style on a CI server
 
+To keep your code base consistently formatted, it can be helpful to fail the CI build
+when a pull request contains unformatted code. Using `--write-mode=diff` instructs
+rustfmt to exit with an error code if the input is not formatted correctly.
+It will also print any found differences.
 
-### Heuristic rather than algorithmic
+(These instructions use the Syntex version of Rustfmt. If you want to use the
+nightly version replace `install rustfmt` with `install rustfmt-nightly`,
+however you must then only run this with the nightly toolchain).
 
-Many formatting tools use a very general algorithmic or even algebraic tool for
-pretty printing. This results in very elegant code, but I believe does not give
-the best results. I prefer a more ad hoc approach where each expression/item is
-formatted using custom rules. We hopefully don't end up with too much code due
-to good old fashioned abstraction and code sharing. This will give a bigger code
-base, but hopefully a better result.
+A minimal Travis setup could look like this:
 
-It also means that there will be some cases we can't format and we have to give
-up. I think that is OK. Hopefully they are rare enough that manually fixing them
-is not painful. Better to have a tool that gives great code in 99% of cases and
-fails in 1% than a tool which gives 50% great code and 50% ugly code, but never
-fails.
+```yaml
+language: rust
+cache: cargo
+before_script:
+- export PATH="$PATH:$HOME/.cargo/bin"
+- which rustfmt || cargo install rustfmt-nightly
+script:
+- cargo fmt -- --write-mode=diff
+- cargo build
+- cargo test
+```
 
+Note that using `cache: cargo` is optional but highly recommended to speed up the installation.
 
-### Incremental development
+## How to build and test
 
-I want rustfmt to be useful as soon as possible and to always be useful. I
-specifically don't want to have to wait for a feature (or worse, the whole tool)
-to be perfect before it is useful. The main ways this is achieved is to output
-the source code where we can't yet reformat, be able to turn off new features
-until they are ready, and the 'do no harm' principle (see next section).
+`cargo build` to build.
 
+`cargo test` to run all tests.
 
-### First, do no harm
+To run rustfmt after this, use `cargo run --bin rustfmt -- filename`. See the
+notes above on running rustfmt.
 
-Until rustfmt it perfect, there will always be a trade-off between doing more and
-doing existing things well. I want to err on the side of the latter.
-Specifically, rustfmt should never take OK code and make it look worse. If we
-can't make it better, we should leave it as is. That might mean being less
-aggressive than we like or using configurability.
 
+## Configuring Rustfmt
 
-### Use the source code as guidance
+Rustfmt is designed to be very configurable. You can create a TOML file called
+`rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent
+directory and it will apply the options in that file. See `rustfmt
+--config-help` for the options which are available, or if you prefer to see
+visual style previews, [Configurations.md](Configurations.md).
 
-There are often multiple ways to format code and satisfy standards. Where this
-is the case, we should use the source code as a hint for reformatting.
-Furthermore, where the code has been formatted in a particular way that satisfies
-the coding standard, it should not be changed (this is sometimes not possible or
-not worthwhile due to uniformity being desirable, but it is a useful goal).
+By default, Rustfmt uses a style which conforms to the [Rust style guide][style
+guide] that has been formalized through the [style RFC
+process][fmt rfcs].
 
+Configuration options are either stable or unstable. Stable options can always
+be used, while unstable ones are only available on a nightly toolchain, and opt-in.
+See [Configurations.md](Configurations.md) for details.
 
-### Architecture details
 
-We use the AST from libsyntax. We use libsyntax's visit module to walk the AST
-to find starting points for reformatting. Eventually, we should reformat everything
-and we shouldn't need the visit module. We keep track of the last formatted
-position in the code, and when we reformat the next piece of code we make sure
-to output the span for all the code in between (handled by missed_spans.rs).
+## Tips
 
-Our visitor keeps track of the desired current indent due to blocks (
-`block_indent`). Each `visit_*` method reformats code according to this indent
-and `IDEAL_WIDTH` and `MAX_WIDTH` (which should one day be supplied from a 
-config file). Most reformatting done in the `visit_*` methods is a bit hackey
-and is meant to be temporary until it can be done properly.
+* For things you do not want rustfmt to mangle, use one of
 
-There are a bunch of methods called `rewrite_*`. There do the bulk of the
-reformatting. These take the AST node to be reformatted (this may not literally
-be an AST node from libsyntax, there might be multiple parameters describing a
-logical node), the current indent, and the current width budget. They return a
-`String` (or sometimes an `Option<String>`) which formats the code in the box
-given by the indent and width budget. If the method fails, it returns `None` and
-the calling method then has to fallback in some way to give the callee more space.
+    ```rust
+    #[rustfmt_skip]  // requires nightly and #![feature(custom_attribute)] in crate root
+    #[cfg_attr(rustfmt, rustfmt_skip)]  // works in stable
+    ```
+* When you run rustfmt, place a file named `rustfmt.toml` or `.rustfmt.toml` in
+  target file directory or its parents to override the default settings of
+  rustfmt. You can generate a file containing the default configuration with
+  `rustfmt --dump-default-config rustfmt.toml` and customize as needed.
+* After successful compilation, a `rustfmt` executable can be found in the
+  target directory.
+* If you're having issues compiling Rustfmt (or compile errors when trying to
+  install), make sure you have the most recent version of Rust installed.
 
-So, in summary to format a node, we calculate the width budget and then walk down
-the tree from the node. At a leaf, we generate an actual string and then unwind,
-combining these strings as we go back up the tree.
+* If you get an error like `error while loading shared libraries` while starting
+  up rustfmt you should try the following:
 
-For example, consider a method definition:
+On Linux:
 
 ```
-    fn foo(a: A, b: B) {
-        ...
-    }
+export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
 ```
 
-We start at indent 4, the rewrite function for the whole function knows it must
-write `fn foo(` before the arguments and `) {` after them, assuming the max width
-is 100, it thus asks the rewrite argument list function to rewrite with an indent
-of 11 and in a width of 86. Assuming that is possible (obviously in this case),
-it returns a string for the arguments and it can make a string for the function
-header. If the arguments couldn't be fitted in that space, we might try to
-fallback to a hanging indent, so we try again with indent 8 and width 89.
-
-
-## Contributing
+On MacOS:
 
-### Test and file issues
+```
+export DYLD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH
+```
 
-It would be really useful to have people use rustfmt on their projects and file
-issues where it does something you don't expect.
+On Windows (Git Bash/Mingw):
 
-A really useful thing to do that on a crate from the Rust repo. If it does
-something unexpected, file an issue; if not, make a PR to the Rust repo with the
-reformatted code. I hope to get the whole repo consistently rustfmt'ed and to
-replace `make tidy` with rustfmt as a medium-term goal.
+```
+export PATH=$(rustc --print sysroot)/lib/rustlib/x86_64-pc-windows-gnu/lib/:$PATH
+```
 
-### Create test cases
+(Substitute `x86_64` by `i686` and `gnu` by `msvc` depending on which version of rustc was used to install rustfmt).
 
-Having a strong test suite for a tool like this is essential. It is very easy
-to create regressions. Any tests you can add are very much appreciated.
+## License
 
-### Hack!
+Rustfmt is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
 
-Here are some [good starting issues](https://github.com/nrc/rustfmt/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy).
-Note than some of those issues tagged 'easy' are not that easy and might be better
-second issues, rather than good first issues to fix.
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.
 
-If you've found areas which need polish and don't have issues, please submit a
-PR, don't feel there needs to be an issue.
+[rust]: https://github.com/rust-lang/rust
+[fmt rfcs]: https://github.com/rust-lang-nursery/fmt-rfcs
+[style guide]: https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md