mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-08 05:47:40 +00:00
Merge remote-tracking branch 'origin/master' into difflines_mode
This commit is contained in:
commit
c2fda14e0a
@ -2,6 +2,11 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Add `use_field_init_shorthand` config option.
|
||||
- Add `reorder_modules` configuration option.
|
||||
|
||||
## [0.3.6] 2018-01-18
|
||||
|
||||
### Fixed
|
||||
|
153
Cargo.lock
generated
153
Cargo.lock
generated
@ -32,6 +32,15 @@ name = "bitflags"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cargo-fmt"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.4.1"
|
||||
@ -106,9 +115,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.15"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "git-rustfmt"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustfmt-config 0.4.0",
|
||||
"rustfmt-core 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.3.4"
|
||||
@ -159,7 +179,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.41"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -185,7 +213,7 @@ version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -197,11 +225,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.20"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -223,7 +262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_cratesio_shim"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -232,57 +271,57 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_data_structures"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_errors"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-serialize"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-syntax"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-syntax_pos"
|
||||
version = "12.0.0"
|
||||
version = "29.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -293,28 +332,56 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "0.3.6"
|
||||
name = "rustfmt-bin"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustfmt-config 0.4.0",
|
||||
"rustfmt-core 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-config"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-core"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustfmt-config 0.4.0",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-format-diff"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -362,7 +429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -497,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9"
|
||||
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
|
||||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
@ -505,20 +572,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
|
||||
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||
"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412"
|
||||
"checksum parking_lot_core 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "9f35048d735bb93dd115a0030498785971aab3234d311fbe273d020084d26bd8"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
|
||||
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
|
||||
"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e"
|
||||
"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc"
|
||||
"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0"
|
||||
"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604"
|
||||
"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c"
|
||||
"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b"
|
||||
"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
|
||||
"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad"
|
||||
"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182"
|
||||
"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b"
|
||||
"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d"
|
||||
"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0"
|
||||
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
|
||||
"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
67
Cargo.toml
67
Cargo.toml
@ -1,58 +1,9 @@
|
||||
[package]
|
||||
|
||||
name = "rustfmt-nightly"
|
||||
version = "0.3.6"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "Tool to find and fix Rust formatting issues"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
build = "build.rs"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "rustfmt"
|
||||
|
||||
[[bin]]
|
||||
name = "cargo-fmt"
|
||||
|
||||
[[bin]]
|
||||
name = "rustfmt-format-diff"
|
||||
|
||||
[[bin]]
|
||||
name = "git-rustfmt"
|
||||
|
||||
[features]
|
||||
default = ["cargo-fmt", "rustfmt-format-diff"]
|
||||
cargo-fmt = []
|
||||
rustfmt-format-diff = []
|
||||
|
||||
[dependencies]
|
||||
toml = "0.4"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
unicode-segmentation = "1.0.0"
|
||||
regex = "0.2"
|
||||
term = "0.4"
|
||||
diff = "0.1"
|
||||
log = "0.3"
|
||||
env_logger = "0.4"
|
||||
getopts = "0.2"
|
||||
derive-new = "0.5"
|
||||
cargo_metadata = "0.4"
|
||||
rustc-ap-syntax = "12.0.0"
|
||||
rustc-ap-rustc_errors = "12.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.0.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.11"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
kernel32-sys = "0.2.2"
|
||||
winapi = "0.2.7"
|
||||
[workspace]
|
||||
members = [
|
||||
"cargo-fmt",
|
||||
"git-rustfmt",
|
||||
"rustfmt-bin",
|
||||
"rustfmt-config",
|
||||
"rustfmt-core",
|
||||
"rustfmt-format-diff",
|
||||
]
|
||||
|
@ -31,27 +31,31 @@ Indent on expressions or items.
|
||||
#### `"Block"` (default):
|
||||
|
||||
```rust
|
||||
let lorem = vec![
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit",
|
||||
];
|
||||
fn main() {
|
||||
let lorem = vec![
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit",
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Visual"`:
|
||||
|
||||
```rust
|
||||
let lorem = vec!["ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit"];
|
||||
fn main() {
|
||||
let lorem = vec!["ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit"];
|
||||
}
|
||||
```
|
||||
|
||||
### Control flow
|
||||
@ -59,21 +63,24 @@ let lorem = vec!["ipsum",
|
||||
#### `"Block"` (default):
|
||||
|
||||
```rust
|
||||
if lorem_ipsum &&
|
||||
dolor_sit &&
|
||||
amet_consectetur
|
||||
{
|
||||
// ...
|
||||
fn main() {
|
||||
if lorem_ipsum && dolor_sit && amet_consectetur && lorem_sit && dolor_consectetur && amet_ipsum
|
||||
&& lorem_consectetur
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Visual"`:
|
||||
|
||||
```rust
|
||||
if lorem_ipsum &&
|
||||
dolor_sit &&
|
||||
amet_consectetur {
|
||||
// ...
|
||||
fn main() {
|
||||
if lorem_ipsum && dolor_sit && amet_consectetur && lorem_sit && dolor_consectetur && amet_ipsum
|
||||
&& lorem_consectetur
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -124,29 +131,33 @@ fn lorem(ipsum: usize,
|
||||
#### `"Block"` (default):
|
||||
|
||||
```rust
|
||||
lorem(
|
||||
"lorem",
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit",
|
||||
);
|
||||
fn main() {
|
||||
lorem(
|
||||
"lorem",
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit",
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Visual"`:
|
||||
|
||||
```rust
|
||||
lorem("lorem",
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit");
|
||||
fn main() {
|
||||
lorem("lorem",
|
||||
"ipsum",
|
||||
"dolor",
|
||||
"sit",
|
||||
"amet",
|
||||
"consectetur",
|
||||
"adipiscing",
|
||||
"elit");
|
||||
}
|
||||
```
|
||||
|
||||
### Generics
|
||||
@ -161,7 +172,7 @@ fn lorem<
|
||||
Amet: Eq = usize,
|
||||
Adipiscing: Eq = usize,
|
||||
Consectetur: Eq = usize,
|
||||
Elit: Eq = usize
|
||||
Elit: Eq = usize,
|
||||
>(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
@ -184,15 +195,15 @@ fn lorem<Ipsum: Eq = usize,
|
||||
Amet: Eq = usize,
|
||||
Adipiscing: Eq = usize,
|
||||
Consectetur: Eq = usize,
|
||||
Elit: Eq = usize>
|
||||
(ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
adipiscing: Adipiscing,
|
||||
consectetur: Consectetur,
|
||||
elit: Elit)
|
||||
-> T {
|
||||
Elit: Eq = usize>(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
adipiscing: Adipiscing,
|
||||
consectetur: Consectetur,
|
||||
elit: Elit)
|
||||
-> T {
|
||||
// body
|
||||
}
|
||||
```
|
||||
@ -202,17 +213,21 @@ fn lorem<Ipsum: Eq = usize,
|
||||
#### `"Block"` (default):
|
||||
|
||||
```rust
|
||||
let lorem = Lorem {
|
||||
ipsum: dolor,
|
||||
sit: amet,
|
||||
};
|
||||
fn main() {
|
||||
let lorem = Lorem {
|
||||
ipsum: dolor,
|
||||
sit: amet,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Visual"`:
|
||||
|
||||
```rust
|
||||
let lorem = Lorem { ipsum: dolor,
|
||||
sit: amet, };
|
||||
fn main() {
|
||||
let lorem = Lorem { ipsum: dolor,
|
||||
sit: amet, };
|
||||
}
|
||||
```
|
||||
|
||||
See also: [`struct_lit_single_line`](#struct_lit_single_line), [`indent_style`](#indent_style).
|
||||
@ -227,7 +242,7 @@ where
|
||||
Ipsum: Eq,
|
||||
Dolor: Eq,
|
||||
Sit: Eq,
|
||||
Amet: Eq
|
||||
Amet: Eq,
|
||||
{
|
||||
// body
|
||||
}
|
||||
@ -274,7 +289,11 @@ fn main() {
|
||||
"adipiscing",
|
||||
);
|
||||
|
||||
let lorem = Lorem { ipsum: dolor, sit: amet };
|
||||
let lorem = Lorem {
|
||||
ipsum: dolor,
|
||||
sit: amet,
|
||||
};
|
||||
let lorem = Lorem { ipsum: dolor };
|
||||
|
||||
let lorem = if ipsum { dolor } else { sit };
|
||||
}
|
||||
@ -319,16 +338,16 @@ Where to put a binary operator when a binary expression goes multiline.
|
||||
#### `"Front"` (default):
|
||||
|
||||
```rust
|
||||
let or = foo
|
||||
|| bar
|
||||
|| foobar;
|
||||
fn main() {
|
||||
let or = foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo
|
||||
|| barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar;
|
||||
|
||||
let sum = 1234
|
||||
+ 5678
|
||||
+ 910;
|
||||
let sum = 123456789012345678901234567890 + 123456789012345678901234567890
|
||||
+ 123456789012345678901234567890;
|
||||
|
||||
let range = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
..bbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
|
||||
let range = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
..bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Back"`:
|
||||
@ -488,13 +507,18 @@ Replace strings of _ wildcards by a single .. in tuple patterns
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
let (lorem, ipsum, _, _) = (1, 2, 3, 4);
|
||||
fn main() {
|
||||
let (lorem, ipsum, _, _) = (1, 2, 3, 4);
|
||||
let (lorem, ipsum, ..) = (1, 2, 3, 4);
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
let (lorem, ipsum, ..) = (1, 2, 3, 4);
|
||||
fn main() {
|
||||
let (lorem, ipsum, ..) = (1, 2, 3, 4);
|
||||
}
|
||||
```
|
||||
|
||||
## `control_brace_style`
|
||||
@ -508,34 +532,40 @@ Brace style for control flow constructs
|
||||
#### `"AlwaysSameLine"` (default):
|
||||
|
||||
```rust
|
||||
if lorem {
|
||||
println!("ipsum!");
|
||||
} else {
|
||||
println!("dolor!");
|
||||
fn main() {
|
||||
if lorem {
|
||||
println!("ipsum!");
|
||||
} else {
|
||||
println!("dolor!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `"AlwaysNextLine"`:
|
||||
|
||||
```rust
|
||||
if lorem
|
||||
{
|
||||
println!("ipsum!");
|
||||
}
|
||||
else
|
||||
{
|
||||
println!("dolor!");
|
||||
fn main() {
|
||||
if lorem
|
||||
{
|
||||
println!("ipsum!");
|
||||
}
|
||||
else
|
||||
{
|
||||
println!("dolor!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `"ClosingNextLine"`:
|
||||
|
||||
```rust
|
||||
if lorem {
|
||||
println!("ipsum!");
|
||||
}
|
||||
else {
|
||||
println!("dolor!");
|
||||
fn main() {
|
||||
if lorem {
|
||||
println!("ipsum!");
|
||||
}
|
||||
else {
|
||||
println!("dolor!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -637,33 +667,41 @@ trait Lorem {
|
||||
|
||||
```rust
|
||||
trait Lorem {
|
||||
fn lorem(ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet);
|
||||
fn lorem(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
);
|
||||
|
||||
fn lorem(ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet) {
|
||||
fn lorem(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
) {
|
||||
// body
|
||||
}
|
||||
|
||||
fn lorem(ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
consectetur: Consectetur,
|
||||
adipiscing: Adipiscing,
|
||||
elit: Elit);
|
||||
fn lorem(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
consectetur: Consectetur,
|
||||
adipiscing: Adipiscing,
|
||||
elit: Elit,
|
||||
);
|
||||
|
||||
fn lorem(ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
consectetur: Consectetur,
|
||||
adipiscing: Adipiscing,
|
||||
elit: Elit) {
|
||||
fn lorem(
|
||||
ipsum: Ipsum,
|
||||
dolor: Dolor,
|
||||
sit: Sit,
|
||||
amet: Amet,
|
||||
consectetur: Consectetur,
|
||||
adipiscing: Adipiscing,
|
||||
elit: Elit,
|
||||
) {
|
||||
// body
|
||||
}
|
||||
}
|
||||
@ -748,7 +786,8 @@ struct Lorem {
|
||||
}
|
||||
|
||||
struct Dolor<T>
|
||||
where T: Eq
|
||||
where
|
||||
T: Eq,
|
||||
{
|
||||
sit: T,
|
||||
}
|
||||
@ -763,7 +802,8 @@ struct Lorem
|
||||
}
|
||||
|
||||
struct Dolor<T>
|
||||
where T: Eq
|
||||
where
|
||||
T: Eq,
|
||||
{
|
||||
sit: T,
|
||||
}
|
||||
@ -777,7 +817,8 @@ struct Lorem {
|
||||
}
|
||||
|
||||
struct Dolor<T>
|
||||
where T: Eq {
|
||||
where
|
||||
T: Eq, {
|
||||
sit: T,
|
||||
}
|
||||
```
|
||||
@ -862,7 +903,7 @@ impl<T> Lorem for T
|
||||
where
|
||||
Option<T>: Ipsum,
|
||||
{
|
||||
...
|
||||
// body
|
||||
}
|
||||
```
|
||||
|
||||
@ -870,8 +911,9 @@ where
|
||||
|
||||
```rust
|
||||
impl<T> Lorem for T
|
||||
where Option<T>: Ipsum {
|
||||
...
|
||||
where Option<T>: Ipsum
|
||||
{
|
||||
// body
|
||||
}
|
||||
```
|
||||
|
||||
@ -915,15 +957,19 @@ Format string literals where necessary
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
let lorem = "ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor sit";
|
||||
fn main() {
|
||||
let lorem =
|
||||
"ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor sit amet consectetur adipiscing";
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
let lorem =
|
||||
"ipsum dolor sit amet consectetur \
|
||||
adipiscing elit lorem ipsum dolor sit";
|
||||
fn main() {
|
||||
let lorem = "ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor sit amet \
|
||||
consectetur adipiscing";
|
||||
}
|
||||
```
|
||||
|
||||
See also [`max_width`](#max_width).
|
||||
@ -966,18 +1012,16 @@ Indent style of imports
|
||||
#### `"Visual"` (default):
|
||||
|
||||
```rust
|
||||
use foo::{xxx,
|
||||
yyy,
|
||||
zzz};
|
||||
use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,
|
||||
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz};
|
||||
```
|
||||
|
||||
#### `"Block"`:
|
||||
|
||||
```rust
|
||||
use foo::{
|
||||
xxx,
|
||||
yyy,
|
||||
zzz,
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,
|
||||
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
|
||||
};
|
||||
```
|
||||
|
||||
@ -994,10 +1038,10 @@ Item layout inside a imports block
|
||||
#### `"Mixed"` (default):
|
||||
|
||||
```rust
|
||||
use foo::{xxx, yyy, zzz};
|
||||
use foo::{xxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz};
|
||||
|
||||
use foo::{aaa, bbb, ccc,
|
||||
ddd, eee, fff};
|
||||
use foo::{aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd,
|
||||
eeeeeeeeeeeeeeeeee, ffffffffffffffffff};
|
||||
```
|
||||
|
||||
#### `"Horizontal"`:
|
||||
@ -1013,14 +1057,14 @@ use foo::{aaa, bbb, ccc, ddd, eee, fff};
|
||||
#### `"HorizontalVertical"`:
|
||||
|
||||
```rust
|
||||
use foo::{xxx, yyy, zzz};
|
||||
use foo::{xxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz};
|
||||
|
||||
use foo::{aaa,
|
||||
bbb,
|
||||
ccc,
|
||||
ddd,
|
||||
eee,
|
||||
fff};
|
||||
use foo::{aaaaaaaaaaaaaaaaaa,
|
||||
bbbbbbbbbbbbbbbbbb,
|
||||
cccccccccccccccccc,
|
||||
dddddddddddddddddd,
|
||||
eeeeeeeeeeeeeeeeee,
|
||||
ffffffffffffffffff};
|
||||
```
|
||||
|
||||
#### `"Vertical"`:
|
||||
@ -1050,22 +1094,26 @@ Put a trailing comma after a block based match arm (non-block arms are not affec
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
match lorem {
|
||||
Lorem::Ipsum => {
|
||||
println!("ipsum");
|
||||
fn main() {
|
||||
match lorem {
|
||||
Lorem::Ipsum => {
|
||||
println!("ipsum");
|
||||
}
|
||||
Lorem::Dolor => println!("dolor"),
|
||||
}
|
||||
Lorem::Dolor => println!("dolor"),
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
match lorem {
|
||||
Lorem::Ipsum => {
|
||||
println!("ipsum");
|
||||
},
|
||||
Lorem::Dolor => println!("dolor"),
|
||||
fn main() {
|
||||
match lorem {
|
||||
Lorem::Ipsum => {
|
||||
println!("ipsum");
|
||||
},
|
||||
Lorem::Dolor => println!("dolor"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1116,37 +1164,40 @@ Force multiline closure and match arm bodies to be wrapped in a block
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
result.and_then(|maybe_value| match maybe_value {
|
||||
None => ...,
|
||||
Some(value) => ...,
|
||||
})
|
||||
fn main() {
|
||||
result.and_then(|maybe_value| match maybe_value {
|
||||
None => foo(),
|
||||
Some(value) => bar(),
|
||||
});
|
||||
|
||||
match lorem {
|
||||
None => if ipsum {
|
||||
println!("Hello World");
|
||||
},
|
||||
Some(dolor) => ...,
|
||||
match lorem {
|
||||
None => if ipsum {
|
||||
println!("Hello World");
|
||||
},
|
||||
Some(dolor) => foo(),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
|
||||
result.and_then(|maybe_value| {
|
||||
match maybe_value {
|
||||
None => ...,
|
||||
Some(value) => ...,
|
||||
}
|
||||
})
|
||||
|
||||
match lorem {
|
||||
None => {
|
||||
if ipsum {
|
||||
println!("Hello World");
|
||||
fn main() {
|
||||
result.and_then(|maybe_value| {
|
||||
match maybe_value {
|
||||
None => foo(),
|
||||
Some(value) => bar(),
|
||||
}
|
||||
});
|
||||
|
||||
match lorem {
|
||||
None => {
|
||||
if ipsum {
|
||||
println!("Hello World");
|
||||
}
|
||||
}
|
||||
Some(dolor) => foo(),
|
||||
}
|
||||
Some(dolor) => ...,
|
||||
}
|
||||
```
|
||||
|
||||
@ -1468,7 +1519,7 @@ struct Foo {
|
||||
|
||||
## `spaces_around_ranges`
|
||||
|
||||
Put spaces around the .. and ... range operators
|
||||
Put spaces around the .., ..=, and ... range operators
|
||||
|
||||
- **Default value**: `false`
|
||||
- **Possible values**: `true`, `false`
|
||||
@ -1477,13 +1528,49 @@ Put spaces around the .. and ... range operators
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
let lorem = 0..10;
|
||||
fn main() {
|
||||
let lorem = 0..10;
|
||||
let ipsum = 0..=10;
|
||||
|
||||
match lorem {
|
||||
1..5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
|
||||
match lorem {
|
||||
1..=5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
|
||||
match lorem {
|
||||
1...5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
let lorem = 0 .. 10;
|
||||
fn main() {
|
||||
let lorem = 0 .. 10;
|
||||
let ipsum = 0 ..= 10;
|
||||
|
||||
match lorem {
|
||||
1 .. 5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
|
||||
match lorem {
|
||||
1 ..= 5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
|
||||
match lorem {
|
||||
1 ... 5 => foo(),
|
||||
_ => bar,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `spaces_within_parens_and_brackets`
|
||||
@ -1508,24 +1595,28 @@ fn lorem<T: Eq>(t: T) {
|
||||
}
|
||||
|
||||
// non-empty square brackets
|
||||
let lorem: [usize; 2] = [ipsum, dolor];
|
||||
fn lorem<T: Eq>(t: T) {
|
||||
let lorem: [usize; 2] = [ipsum, dolor];
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
// generic arguments
|
||||
fn lorem< T: Eq >(t: T) {
|
||||
fn lorem< T: Eq >( t: T ) {
|
||||
// body
|
||||
}
|
||||
|
||||
// non-empty parentheses
|
||||
fn lorem<T: Eq>( t: T ) {
|
||||
fn lorem< T: Eq >( t: T ) {
|
||||
let lorem = ( ipsum, dolor );
|
||||
}
|
||||
|
||||
// non-empty square brackets
|
||||
let lorem: [ usize; 2 ] = [ ipsum, dolor ];
|
||||
fn lorem< T: Eq >( t: T ) {
|
||||
let lorem: [ usize; 2 ] = [ ipsum, dolor ];
|
||||
}
|
||||
```
|
||||
|
||||
## `struct_lit_single_line`
|
||||
@ -1545,10 +1636,12 @@ let lorem = Lorem { ipsum: dolor, sit: amet };
|
||||
#### `false`:
|
||||
|
||||
```rust
|
||||
let lorem = Lorem {
|
||||
ipsum: dolor,
|
||||
sit: amet,
|
||||
};
|
||||
fn main() {
|
||||
let lorem = Lorem {
|
||||
ipsum: dolor,
|
||||
sit: amet,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
See also: [`indent_style`](#indent_style).
|
||||
@ -1568,7 +1661,7 @@ Number of spaces per tab
|
||||
fn lorem() {
|
||||
let ipsum = dolor();
|
||||
let sit = vec![
|
||||
"amet consectetur adipiscing elit."
|
||||
"amet consectetur adipiscing elit amet consectetur adipiscing elit amet consectetur.",
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -1579,7 +1672,7 @@ fn lorem() {
|
||||
fn lorem() {
|
||||
let ipsum = dolor();
|
||||
let sit = vec![
|
||||
"amet consectetur adipiscing elit."
|
||||
"amet consectetur adipiscing elit amet consectetur adipiscing elit amet consectetur.",
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -1598,43 +1691,49 @@ How to handle trailing commas for lists
|
||||
#### `"Vertical"` (default):
|
||||
|
||||
```rust
|
||||
let Lorem { ipsum, dolor, sit } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing,
|
||||
} = elit;
|
||||
fn main() {
|
||||
let Lorem { ipsum, dolor, sit } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing,
|
||||
} = elit;
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Always"`:
|
||||
|
||||
```rust
|
||||
let Lorem { ipsum, dolor, sit, } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing,
|
||||
} = elit;
|
||||
fn main() {
|
||||
let Lorem { ipsum, dolor, sit, } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing,
|
||||
} = elit;
|
||||
}
|
||||
```
|
||||
|
||||
#### `"Never"`:
|
||||
|
||||
```rust
|
||||
let Lorem { ipsum, dolor, sit } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing
|
||||
} = elit;
|
||||
fn main() {
|
||||
let Lorem { ipsum, dolor, sit } = amet;
|
||||
let Lorem {
|
||||
ipsum,
|
||||
dolor,
|
||||
sit,
|
||||
amet,
|
||||
consectetur,
|
||||
adipiscing
|
||||
} = elit;
|
||||
}
|
||||
```
|
||||
|
||||
See also: [`match_block_trailing_comma`](#match_block_trailing_comma).
|
||||
@ -1673,7 +1772,7 @@ Determines if `+` or `=` are wrapped in spaces in the punctuation of types
|
||||
|
||||
```rust
|
||||
fn lorem<Ipsum: Dolor + Sit = Amet>() {
|
||||
// body
|
||||
// body
|
||||
}
|
||||
```
|
||||
|
||||
@ -1681,7 +1780,49 @@ fn lorem<Ipsum: Dolor + Sit = Amet>() {
|
||||
|
||||
```rust
|
||||
fn lorem<Ipsum: Dolor+Sit=Amet>() {
|
||||
// body
|
||||
// body
|
||||
}
|
||||
```
|
||||
|
||||
## `use_field_init_shorthand`
|
||||
|
||||
Use field initialize shorthand if possible.
|
||||
|
||||
- **Default value**: `false`
|
||||
- **Possible values**: `true`, `false`
|
||||
- **Stable**: No
|
||||
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
let z = 3;
|
||||
let a = Foo { x: x, y: y, z: z };
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
let z = 3;
|
||||
let a = Foo { x, y, z };
|
||||
}
|
||||
```
|
||||
|
||||
@ -1696,13 +1837,17 @@ Replace uses of the try! macro by the ? shorthand
|
||||
#### `false` (default):
|
||||
|
||||
```rust
|
||||
let lorem = try!(ipsum.map(|dolor|dolor.sit()));
|
||||
fn main() {
|
||||
let lorem = try!(ipsum.map(|dolor| dolor.sit()));
|
||||
}
|
||||
```
|
||||
|
||||
#### `true`:
|
||||
|
||||
```rust
|
||||
let lorem = ipsum.map(|dolor| dolor.sit())?;
|
||||
fn main() {
|
||||
let lorem = ipsum.map(|dolor| dolor.sit())?;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -1741,21 +1886,25 @@ Wrap the body of arms in blocks when it does not fit on the same line with the p
|
||||
#### `true` (default):
|
||||
|
||||
```rust
|
||||
match lorem {
|
||||
true => {
|
||||
foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x)
|
||||
fn main() {
|
||||
match lorem {
|
||||
true => {
|
||||
foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x)
|
||||
}
|
||||
false => println!("{}", sit),
|
||||
}
|
||||
false => println!("{}", sit),
|
||||
}
|
||||
```
|
||||
|
||||
#### `false`:
|
||||
|
||||
```rust
|
||||
match lorem {
|
||||
true =>
|
||||
foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x),
|
||||
false => println!("{}", sit),
|
||||
fn main() {
|
||||
match lorem {
|
||||
true =>
|
||||
foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x),
|
||||
false => println!("{}", sit),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1782,6 +1931,8 @@ lines are found, they are trimmed down to match this integer.
|
||||
Original Code:
|
||||
|
||||
```rust
|
||||
#![rustfmt_skip]
|
||||
|
||||
fn foo() {
|
||||
println!("a");
|
||||
}
|
||||
@ -1839,6 +1990,8 @@ them, additional blank lines are inserted.
|
||||
Original Code (rustfmt will not change it with the default value of `0`):
|
||||
|
||||
```rust
|
||||
#![rustfmt_skip]
|
||||
|
||||
fn foo() {
|
||||
println!("a");
|
||||
}
|
||||
|
39
README.md
39
README.md
@ -21,31 +21,29 @@ to be a bit out of date). Version 0.1 of rustfmt-nightly is forked from version
|
||||
|
||||
## Quick start
|
||||
|
||||
You must be using the latest nightly compiler toolchain.
|
||||
Currently, you can use `rustfmt` on nightly and beta. Rust 1.24 stable will work,
|
||||
but we're not quite there yet!
|
||||
|
||||
To install:
|
||||
|
||||
```
|
||||
cargo install rustfmt-nightly
|
||||
rustup component add rustfmt-preview --toolchain=nightly
|
||||
```
|
||||
|
||||
If `nightly` is your default toolchain, you can leave the `--toolchain` off.
|
||||
|
||||
to run on a cargo project in the current working directory:
|
||||
|
||||
```
|
||||
cargo fmt
|
||||
cargo +nightly fmt
|
||||
```
|
||||
|
||||
If `nightly` is your default toolchain, you can leave off the `+nightly`.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
cargo install rustfmt-nightly
|
||||
```
|
||||
|
||||
or if you're using [Rustup](https://www.rustup.rs/)
|
||||
|
||||
```
|
||||
rustup update
|
||||
rustup run nightly cargo install rustfmt-nightly
|
||||
rustup component add rustfmt-preview --toolchain=nightly
|
||||
```
|
||||
|
||||
If you don't have a nightly toolchain, you can add it using rustup:
|
||||
@ -63,12 +61,6 @@ rustup default nightly
|
||||
If you choose not to do that you'll have to run rustfmt using `rustup run ...`
|
||||
or by adding `+nightly` to the cargo invocation.
|
||||
|
||||
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
|
||||
|
||||
To install from source, first checkout to the tag or branch you want to install, then issue
|
||||
@ -151,25 +143,20 @@ when a pull request contains unformatted code. Using `--write-mode=diff` instruc
|
||||
rustfmt to exit with an error code if the input is not formatted correctly.
|
||||
It will also print any found differences.
|
||||
|
||||
(These instructions use the nightly version of Rustfmt. If you want to use the
|
||||
Syntex version replace `install rustfmt-nightly` with `install rustfmt`).
|
||||
|
||||
A minimal Travis setup could look like this:
|
||||
|
||||
```yaml
|
||||
language: rust
|
||||
cache: cargo
|
||||
before_script:
|
||||
- export PATH="$PATH:$HOME/.cargo/bin"
|
||||
- which rustfmt || cargo install rustfmt-nightly
|
||||
- rustup toolchain install nightly
|
||||
- rustup component add --toolchain nightly rustfmt-preview
|
||||
- which rustfmt || cargo install --force rustfmt-nightly
|
||||
script:
|
||||
- cargo fmt -- --write-mode=diff
|
||||
- cargo +nightly fmt --all -- --write-mode=diff
|
||||
- cargo build
|
||||
- cargo test
|
||||
```
|
||||
|
||||
Note that using `cache: cargo` is optional but highly recommended to speed up the installation.
|
||||
|
||||
## How to build and test
|
||||
|
||||
`cargo build` to build.
|
||||
|
@ -47,9 +47,6 @@ install:
|
||||
# ???
|
||||
build: false
|
||||
|
||||
# Build rustfmt, run the executables as
|
||||
test_script:
|
||||
- cargo build --verbose
|
||||
- cargo run --bin rustfmt -- --help
|
||||
- cargo run --bin cargo-fmt -- --help
|
||||
- cargo test
|
||||
|
17
cargo-fmt/Cargo.toml
Normal file
17
cargo-fmt/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "cargo-fmt"
|
||||
version = "0.4.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "Cargo frontend for rustfmt"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[[bin]]
|
||||
name = "cargo-fmt"
|
||||
|
||||
[dependencies]
|
||||
cargo_metadata = "0.4"
|
||||
getopts = "0.2"
|
||||
serde_json = "1.0"
|
@ -97,14 +97,14 @@ fn execute() -> i32 {
|
||||
}
|
||||
|
||||
macro_rules! print_usage {
|
||||
($print:ident, $opts:ident, $reason:expr) => ({
|
||||
($print: ident, $opts: ident, $reason: expr) => {{
|
||||
let msg = format!("{}\nusage: cargo fmt [options]", $reason);
|
||||
$print!(
|
||||
"{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
|
||||
Arguments after `--` are passed to rustfmt.",
|
||||
$opts.usage(&msg)
|
||||
);
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
fn print_usage_to_stdout(opts: &Options, reason: &str) {
|
19
git-rustfmt/Cargo.toml
Normal file
19
git-rustfmt/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "git-rustfmt"
|
||||
version = "0.4.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "Run rustfmt against git diff"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[[bin]]
|
||||
name = "git-rustfmt"
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.4"
|
||||
getopts = "0.2"
|
||||
log = "0.3"
|
||||
rustfmt-config = { path = "../rustfmt-config" }
|
||||
rustfmt-core = { path = "../rustfmt-core" }
|
@ -1,8 +1,19 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate env_logger;
|
||||
extern crate getopts;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustfmt_nightly as rustfmt;
|
||||
extern crate rustfmt_config as config;
|
||||
extern crate rustfmt_core as rustfmt;
|
||||
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -12,7 +23,6 @@ use std::str::FromStr;
|
||||
use getopts::{Matches, Options};
|
||||
|
||||
use rustfmt::{run, Input};
|
||||
use rustfmt::config;
|
||||
|
||||
fn prune_files(files: Vec<&str>) -> Vec<&str> {
|
||||
let prefixes: Vec<_> = files
|
20
rustfmt-bin/Cargo.toml
Normal file
20
rustfmt-bin/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "rustfmt-bin"
|
||||
version = "0.4.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "Tool to find and fix Rust formatting issues"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
build = "build.rs"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[[bin]]
|
||||
name = "rustfmt"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.4"
|
||||
getopts = "0.2"
|
||||
rustfmt-config = { path = "../rustfmt-config" }
|
||||
rustfmt-core = { path = "../rustfmt-core" }
|
49
rustfmt-bin/build.rs
Normal file
49
rustfmt-bin/build.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
File::create(out_dir.join("commit-info.txt"))
|
||||
.unwrap()
|
||||
.write_all(commit_info().as_bytes())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Try to get hash and date of the last commit on a best effort basis. If anything goes wrong
|
||||
// (git not installed or if this is not a git repository) just return an empty string.
|
||||
fn commit_info() -> String {
|
||||
match (commit_hash(), commit_date()) {
|
||||
(Some(hash), Some(date)) => format!(" ({} {})", hash.trim_right(), date),
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn commit_hash() -> Option<String> {
|
||||
Command::new("git")
|
||||
.args(&["rev-parse", "--short", "HEAD"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|r| String::from_utf8(r.stdout).ok())
|
||||
}
|
||||
|
||||
fn commit_date() -> Option<String> {
|
||||
Command::new("git")
|
||||
.args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|r| String::from_utf8(r.stdout).ok())
|
||||
}
|
@ -8,24 +8,25 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![cfg(not(test))]
|
||||
|
||||
extern crate env_logger;
|
||||
extern crate getopts;
|
||||
extern crate rustfmt_nightly as rustfmt;
|
||||
extern crate rustfmt_config as config;
|
||||
extern crate rustfmt_core as rustfmt;
|
||||
|
||||
use std::{env, error};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use getopts::{Matches, Options};
|
||||
|
||||
use config::{get_toml_path, Color, Config, WriteMode};
|
||||
use config::file_lines::FileLines;
|
||||
use rustfmt::{run, FileName, Input, Summary};
|
||||
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
|
||||
use rustfmt::file_lines::FileLines;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
type FmtError = Box<error::Error + Send + Sync>;
|
||||
type FmtResult<T> = std::result::Result<T, FmtError>;
|
||||
@ -387,7 +388,7 @@ fn print_usage_to_stdout(opts: &Options, reason: &str) {
|
||||
fn print_version() {
|
||||
println!(
|
||||
"{}-nightly{}",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
|
||||
include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
|
||||
)
|
||||
}
|
||||
@ -453,7 +454,7 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
|
||||
|
||||
return Ok(Operation::Stdin {
|
||||
input: buffer,
|
||||
config_path: config_path,
|
||||
config_path,
|
||||
});
|
||||
}
|
||||
|
||||
@ -469,8 +470,8 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
|
||||
.collect();
|
||||
|
||||
Ok(Operation::Format {
|
||||
files: files,
|
||||
config_path: config_path,
|
||||
minimal_config_path: minimal_config_path,
|
||||
files,
|
||||
config_path,
|
||||
minimal_config_path,
|
||||
})
|
||||
}
|
16
rustfmt-config/Cargo.toml
Normal file
16
rustfmt-config/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "rustfmt-config"
|
||||
version = "0.4.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "A library for configuring and customizing rustfmt"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[dependencies]
|
||||
rustc-ap-syntax = "29.0.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
toml = "0.4"
|
380
rustfmt-config/src/config_type.rs
Normal file
380
rustfmt-config/src/config_type.rs
Normal file
@ -0,0 +1,380 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use file_lines::FileLines;
|
||||
use options::WidthHeuristics;
|
||||
|
||||
/// Trait for types that can be used in `Config`.
|
||||
pub trait ConfigType: Sized {
|
||||
/// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
|
||||
/// pipe-separated list of variants; for other types it returns "<type>".
|
||||
fn doc_hint() -> String;
|
||||
}
|
||||
|
||||
impl ConfigType for bool {
|
||||
fn doc_hint() -> String {
|
||||
String::from("<boolean>")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for usize {
|
||||
fn doc_hint() -> String {
|
||||
String::from("<unsigned integer>")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for isize {
|
||||
fn doc_hint() -> String {
|
||||
String::from("<signed integer>")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for String {
|
||||
fn doc_hint() -> String {
|
||||
String::from("<string>")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for FileLines {
|
||||
fn doc_hint() -> String {
|
||||
String::from("<json>")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for WidthHeuristics {
|
||||
fn doc_hint() -> String {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if we're in a nightly build.
|
||||
///
|
||||
/// The environment variable `CFG_RELEASE_CHANNEL` is set during the rustc bootstrap
|
||||
/// to "stable", "beta", or "nightly" depending on what toolchain is being built.
|
||||
/// If we are being built as part of the stable or beta toolchains, we want
|
||||
/// to disable unstable configuration options.
|
||||
///
|
||||
/// If we're being built by cargo (e.g. `cargo +nightly install rustfmt-nightly`),
|
||||
/// `CFG_RELEASE_CHANNEL` is not set. As we only support being built against the
|
||||
/// nightly compiler when installed from crates.io, default to nightly mode.
|
||||
macro_rules! is_nightly_channel {
|
||||
() => {
|
||||
option_env!("CFG_RELEASE_CHANNEL")
|
||||
.map(|c| c == "nightly")
|
||||
.unwrap_or(true)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! create_config {
|
||||
($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
// For each config item, we store a bool indicating whether it has
|
||||
// been accessed and the value, and a bool whether the option was
|
||||
// manually initialised, or taken from the default,
|
||||
$($i: (Cell<bool>, bool, $ty, bool)),+
|
||||
}
|
||||
|
||||
// Just like the Config struct but with each property wrapped
|
||||
// as Option<T>. This is used to parse a rustfmt.toml that doesn't
|
||||
// specify all properties of `Config`.
|
||||
// We first parse into `PartialConfig`, then create a default `Config`
|
||||
// and overwrite the properties with corresponding values from `PartialConfig`.
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct PartialConfig {
|
||||
$(pub $i: Option<$ty>),+
|
||||
}
|
||||
|
||||
impl PartialConfig {
|
||||
pub fn to_toml(&self) -> Result<String, String> {
|
||||
// Non-user-facing options can't be specified in TOML
|
||||
let mut cloned = self.clone();
|
||||
cloned.file_lines = None;
|
||||
cloned.verbose = None;
|
||||
cloned.width_heuristics = None;
|
||||
|
||||
toml::to_string(&cloned)
|
||||
.map_err(|e| format!("Could not output config: {}", e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
// Macro hygiene won't allow us to make `set_$i()` methods on Config
|
||||
// for each item, so this struct is used to give the API to set values:
|
||||
// `config.set().option(false)`. It's pretty ugly. Consider replacing
|
||||
// with `config.set_option(false)` if we ever get a stable/usable
|
||||
// `concat_idents!()`.
|
||||
pub struct ConfigSetter<'a>(&'a mut Config);
|
||||
|
||||
impl<'a> ConfigSetter<'a> {
|
||||
$(
|
||||
pub fn $i(&mut self, value: $ty) {
|
||||
(self.0).$i.2 = value;
|
||||
if stringify!($i) == "use_small_heuristics" {
|
||||
self.0.set_heuristics();
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
||||
// Query each option, returns true if the user set the option, false if
|
||||
// a default was used.
|
||||
pub struct ConfigWasSet<'a>(&'a Config);
|
||||
|
||||
impl<'a> ConfigWasSet<'a> {
|
||||
$(
|
||||
pub fn $i(&self) -> bool {
|
||||
(self.0).$i.1
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn version_meets_requirement(&self, error_summary: &mut Summary) -> bool {
|
||||
if self.was_set().required_version() {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let required_version = self.required_version();
|
||||
if version != required_version {
|
||||
println!(
|
||||
"Error: rustfmt version ({}) doesn't match the required version ({})",
|
||||
version,
|
||||
required_version,
|
||||
);
|
||||
error_summary.add_formatting_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
$(
|
||||
pub fn $i(&self) -> $ty {
|
||||
self.$i.0.set(true);
|
||||
self.$i.2.clone()
|
||||
}
|
||||
)+
|
||||
|
||||
pub fn set<'a>(&'a mut self) -> ConfigSetter<'a> {
|
||||
ConfigSetter(self)
|
||||
}
|
||||
|
||||
pub fn was_set<'a>(&'a self) -> ConfigWasSet<'a> {
|
||||
ConfigWasSet(self)
|
||||
}
|
||||
|
||||
fn fill_from_parsed_config(mut self, parsed: PartialConfig) -> Config {
|
||||
$(
|
||||
if let Some(val) = parsed.$i {
|
||||
if self.$i.3 {
|
||||
self.$i.1 = true;
|
||||
self.$i.2 = val;
|
||||
} else {
|
||||
if is_nightly_channel!() {
|
||||
self.$i.1 = true;
|
||||
self.$i.2 = val;
|
||||
} else {
|
||||
eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \
|
||||
available in nightly channel.", stringify!($i), val);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
self.set_heuristics();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn from_toml(toml: &str) -> Result<Config, String> {
|
||||
let parsed: toml::Value =
|
||||
toml.parse().map_err(|e| format!("Could not parse TOML: {}", e))?;
|
||||
let mut err: String = String::new();
|
||||
{
|
||||
let table = parsed
|
||||
.as_table()
|
||||
.ok_or(String::from("Parsed config was not table"))?;
|
||||
for key in table.keys() {
|
||||
match &**key {
|
||||
$(
|
||||
stringify!($i) => (),
|
||||
)+
|
||||
_ => {
|
||||
let msg =
|
||||
&format!("Warning: Unknown configuration option `{}`\n", key);
|
||||
err.push_str(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match parsed.try_into() {
|
||||
Ok(parsed_config) => {
|
||||
if !err.is_empty() {
|
||||
eprint!("{}", err);
|
||||
}
|
||||
Ok(Config::default().fill_from_parsed_config(parsed_config))
|
||||
}
|
||||
Err(e) => {
|
||||
err.push_str("Error: Decoding config file failed:\n");
|
||||
err.push_str(format!("{}\n", e).as_str());
|
||||
err.push_str("Please check your config file.");
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn used_options(&self) -> PartialConfig {
|
||||
PartialConfig {
|
||||
$(
|
||||
$i: if self.$i.0.get() {
|
||||
Some(self.$i.2.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_options(&self) -> PartialConfig {
|
||||
PartialConfig {
|
||||
$(
|
||||
$i: Some(self.$i.2.clone()),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn override_value(&mut self, key: &str, val: &str)
|
||||
{
|
||||
match key {
|
||||
$(
|
||||
stringify!($i) => {
|
||||
self.$i.2 = val.parse::<$ty>()
|
||||
.expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
|
||||
stringify!($i),
|
||||
val,
|
||||
stringify!($ty)));
|
||||
}
|
||||
)+
|
||||
_ => panic!("Unknown config key in override: {}", key)
|
||||
}
|
||||
|
||||
if key == "use_small_heuristics" {
|
||||
self.set_heuristics();
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Config` from the toml file specified at `file_path`.
|
||||
///
|
||||
/// This method only looks at the provided path, for a method that
|
||||
/// searches parents for a `rustfmt.toml` see `from_resolved_toml_path`.
|
||||
///
|
||||
/// Return a `Config` if the config could be read and parsed from
|
||||
/// the file, Error otherwise.
|
||||
pub fn from_toml_path(file_path: &Path) -> Result<Config, Error> {
|
||||
let mut file = File::open(&file_path)?;
|
||||
let mut toml = String::new();
|
||||
file.read_to_string(&mut toml)?;
|
||||
Config::from_toml(&toml).map_err(|err| Error::new(ErrorKind::InvalidData, err))
|
||||
}
|
||||
|
||||
/// Resolve the config for input in `dir`.
|
||||
///
|
||||
/// Searches for `rustfmt.toml` beginning with `dir`, and
|
||||
/// recursively checking parents of `dir` if no config file is found.
|
||||
/// If no config file exists in `dir` or in any parent, a
|
||||
/// default `Config` will be returned (and the returned path will be empty).
|
||||
///
|
||||
/// Returns the `Config` to use, and the path of the project file if there was
|
||||
/// one.
|
||||
pub fn from_resolved_toml_path(dir: &Path) -> Result<(Config, Option<PathBuf>), Error> {
|
||||
|
||||
/// Try to find a project file in the given directory and its parents.
|
||||
/// Returns the path of a the nearest project file if one exists,
|
||||
/// or `None` if no project file was found.
|
||||
fn resolve_project_file(dir: &Path) -> Result<Option<PathBuf>, Error> {
|
||||
let mut current = if dir.is_relative() {
|
||||
env::current_dir()?.join(dir)
|
||||
} else {
|
||||
dir.to_path_buf()
|
||||
};
|
||||
|
||||
current = fs::canonicalize(current)?;
|
||||
|
||||
loop {
|
||||
match get_toml_path(¤t) {
|
||||
Ok(Some(path)) => return Ok(Some(path)),
|
||||
Err(e) => return Err(e),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
// If the current directory has no parent, we're done searching.
|
||||
if !current.pop() {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match resolve_project_file(dir)? {
|
||||
None => Ok((Config::default(), None)),
|
||||
Some(path) => Config::from_toml_path(&path).map(|config| (config, Some(path))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn print_docs() {
|
||||
use std::cmp;
|
||||
const HIDE_OPTIONS: [&str; 3] = ["verbose", "file_lines", "width_heuristics"];
|
||||
let max = 0;
|
||||
$( let max = cmp::max(max, stringify!($i).len()+1); )+
|
||||
let mut space_str = String::with_capacity(max);
|
||||
for _ in 0..max {
|
||||
space_str.push(' ');
|
||||
}
|
||||
println!("Configuration Options:");
|
||||
$(
|
||||
let name_raw = stringify!($i);
|
||||
|
||||
if !HIDE_OPTIONS.contains(&name_raw) {
|
||||
let mut name_out = String::with_capacity(max);
|
||||
for _ in name_raw.len()..max-1 {
|
||||
name_out.push(' ')
|
||||
}
|
||||
name_out.push_str(name_raw);
|
||||
name_out.push(' ');
|
||||
println!("{}{} Default: {:?}",
|
||||
name_out,
|
||||
<$ty>::doc_hint(),
|
||||
$def);
|
||||
$(
|
||||
println!("{}{}", space_str, $dstring);
|
||||
)+
|
||||
println!();
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
||||
fn set_heuristics(&mut self) {
|
||||
if self.use_small_heuristics.2 {
|
||||
self.set().width_heuristics(WidthHeuristics::default());
|
||||
} else {
|
||||
self.set().width_heuristics(WidthHeuristics::null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Template for the default configuration
|
||||
impl Default for Config {
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
$(
|
||||
$i: (Cell::new(false), false, $def, $stb),
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -12,12 +12,25 @@
|
||||
|
||||
use std::{cmp, iter, str};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
use serde_json as json;
|
||||
|
||||
use codemap::LineRange;
|
||||
use syntax::codemap::FileName;
|
||||
use syntax::codemap::{FileMap, FileName};
|
||||
|
||||
/// A range of lines in a file, inclusive of both ends.
|
||||
pub struct LineRange {
|
||||
pub file: Rc<FileMap>,
|
||||
pub lo: usize,
|
||||
pub hi: usize,
|
||||
}
|
||||
|
||||
impl LineRange {
|
||||
pub fn file_name(&self) -> &FileName {
|
||||
&self.file.name
|
||||
}
|
||||
}
|
||||
|
||||
/// A range that is inclusive of both ends.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize)]
|
||||
@ -34,7 +47,7 @@ impl<'a> From<&'a LineRange> for Range {
|
||||
|
||||
impl Range {
|
||||
pub fn new(lo: usize, hi: usize) -> Range {
|
||||
Range { lo: lo, hi: hi }
|
||||
Range { lo, hi }
|
||||
}
|
||||
|
||||
fn is_empty(self) -> bool {
|
252
rustfmt-config/src/lib.rs
Normal file
252
rustfmt-config/src/lib.rs
Normal file
@ -0,0 +1,252 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate syntax;
|
||||
extern crate toml;
|
||||
|
||||
use std::{env, fs};
|
||||
use std::cell::Cell;
|
||||
use std::default::Default;
|
||||
use std::fs::File;
|
||||
use std::io::{Error, ErrorKind, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[macro_use]
|
||||
mod config_type;
|
||||
#[macro_use]
|
||||
mod options;
|
||||
|
||||
pub mod file_lines;
|
||||
pub mod lists;
|
||||
pub mod summary;
|
||||
|
||||
use config_type::ConfigType;
|
||||
use file_lines::FileLines;
|
||||
pub use lists::*;
|
||||
pub use options::*;
|
||||
use summary::Summary;
|
||||
|
||||
/// This macro defines configuration options used in rustfmt. Each option
|
||||
/// is defined as follows:
|
||||
///
|
||||
/// `name: value type, default value, is stable, description;`
|
||||
create_config! {
|
||||
// Fundamental stuff
|
||||
max_width: usize, 100, true, "Maximum width of each line";
|
||||
hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
|
||||
tab_spaces: usize, 4, true, "Number of spaces per tab";
|
||||
newline_style: NewlineStyle, NewlineStyle::Unix, true, "Unix or Windows line endings";
|
||||
indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items.";
|
||||
use_small_heuristics: bool, true, false, "Whether to use different formatting for items and\
|
||||
expressions if they satisfy a heuristic notion of 'small'.";
|
||||
|
||||
// strings and comments
|
||||
format_strings: bool, false, false, "Format string literals where necessary";
|
||||
wrap_comments: bool, false, true, "Break comments to fit on the line";
|
||||
comment_width: usize, 80, false,
|
||||
"Maximum length of comments. No effect unless wrap_comments = true";
|
||||
normalize_comments: bool, false, true, "Convert /* */ comments to // comments where possible";
|
||||
|
||||
// Single line expressions and items.
|
||||
empty_item_single_line: bool, true, false,
|
||||
"Put empty-body functions and impls on a single line";
|
||||
struct_lit_single_line: bool, true, false,
|
||||
"Put small struct literals on a single line";
|
||||
fn_single_line: bool, false, false, "Put single-expression functions on a single line";
|
||||
where_single_line: bool, false, false, "To force single line where layout";
|
||||
|
||||
// Imports
|
||||
imports_indent: IndentStyle, IndentStyle::Visual, false, "Indent of imports";
|
||||
imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";
|
||||
|
||||
// Ordering
|
||||
reorder_extern_crates: bool, true, false, "Reorder extern crate statements alphabetically";
|
||||
reorder_extern_crates_in_group: bool, true, false, "Reorder extern crate statements in group";
|
||||
reorder_imports: bool, false, false, "Reorder import statements alphabetically";
|
||||
reorder_imports_in_group: bool, false, false, "Reorder import statements in group";
|
||||
reorder_imported_names: bool, true, false,
|
||||
"Reorder lists of names in import statements alphabetically";
|
||||
reorder_modules: bool, false, false, "Reorder module statemtents alphabetically in group";
|
||||
|
||||
// Spaces around punctuation
|
||||
binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
|
||||
"Where to put a binary operator when a binary expression goes multiline.";
|
||||
type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
|
||||
"Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
|
||||
space_before_colon: bool, false, false, "Leave a space before the colon";
|
||||
space_after_colon: bool, true, false, "Leave a space after the colon";
|
||||
spaces_around_ranges: bool, false, false, "Put spaces around the .. and ... range operators";
|
||||
spaces_within_parens_and_brackets: bool, false, false,
|
||||
"Put spaces within non-empty parentheses or brackets";
|
||||
|
||||
// Misc.
|
||||
combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
|
||||
struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \
|
||||
threshold.";
|
||||
remove_blank_lines_at_start_or_end_of_block: bool, true, false,
|
||||
"Remove blank lines at start or end of a block";
|
||||
match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
|
||||
the same line with the pattern of arms";
|
||||
force_multiline_blocks: bool, false, false,
|
||||
"Force multiline closure bodies and match arms to be wrapped in a block";
|
||||
fn_args_density: Density, Density::Tall, false, "Argument density in functions";
|
||||
brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
|
||||
control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
|
||||
"Brace style for control flow constructs";
|
||||
trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
|
||||
"How to handle trailing commas for lists";
|
||||
trailing_semicolon: bool, true, false,
|
||||
"Add trailing semicolon after break, continue and return";
|
||||
match_block_trailing_comma: bool, false, false,
|
||||
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
|
||||
blank_lines_upper_bound: usize, 1, false,
|
||||
"Maximum number of blank lines which can be put between items.";
|
||||
blank_lines_lower_bound: usize, 0, false,
|
||||
"Minimum number of blank lines which must be put between items.";
|
||||
|
||||
// Options that can change the source code beyond whitespace/blocks (somewhat linty things)
|
||||
merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
|
||||
use_try_shorthand: bool, false, false, "Replace uses of the try! macro by the ? shorthand";
|
||||
condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
|
||||
in tuple patterns";
|
||||
force_explicit_abi: bool, true, true, "Always print the abi for extern items";
|
||||
use_field_init_shorthand: bool, false, false, "Use field initialization shorthand if possible";
|
||||
|
||||
// Control options (changes the operation of rustfmt, rather than the formatting)
|
||||
write_mode: WriteMode, WriteMode::Overwrite, false,
|
||||
"What Write Mode to use when none is supplied: \
|
||||
Replace, Overwrite, Display, Plain, Diff, Coverage";
|
||||
color: Color, Color::Auto, false,
|
||||
"What Color option to use when none is supplied: Always, Never, Auto";
|
||||
required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
|
||||
"Require a specific version of rustfmt.";
|
||||
unstable_features: bool, false, true,
|
||||
"Enables unstable features. Only available on nightly channel";
|
||||
disable_all_formatting: bool, false, false, "Don't reformat anything";
|
||||
skip_children: bool, false, false, "Don't reformat out of line modules";
|
||||
hide_parse_errors: bool, false, false, "Hide errors from the parser";
|
||||
error_on_line_overflow: bool, true, false, "Error if unable to get all lines within max_width";
|
||||
error_on_unformatted: bool, false, false,
|
||||
"Error if unable to get comments or string literals within max_width, \
|
||||
or they are left with trailing whitespaces";
|
||||
report_todo: ReportTactic, ReportTactic::Never, false,
|
||||
"Report all, none or unnumbered occurrences of TODO in source file comments";
|
||||
report_fixme: ReportTactic, ReportTactic::Never, false,
|
||||
"Report all, none or unnumbered occurrences of FIXME in source file comments";
|
||||
|
||||
// Not user-facing.
|
||||
verbose: bool, false, false, "Use verbose output";
|
||||
file_lines: FileLines, FileLines::all(), false,
|
||||
"Lines to format; this is not supported in rustfmt.toml, and can only be specified \
|
||||
via the --file-lines option";
|
||||
width_heuristics: WidthHeuristics, WidthHeuristics::default(), false,
|
||||
"'small' heuristic values";
|
||||
}
|
||||
|
||||
/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
|
||||
///
|
||||
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
|
||||
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
|
||||
const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
|
||||
for config_file_name in &CONFIG_FILE_NAMES {
|
||||
let config_file = dir.join(config_file_name);
|
||||
match fs::metadata(&config_file) {
|
||||
// Only return if it's a file to handle the unlikely situation of a directory named
|
||||
// `rustfmt.toml`.
|
||||
Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
|
||||
// Return the error if it's something other than `NotFound`; otherwise we didn't
|
||||
// find the project file yet, and continue searching.
|
||||
Err(e) => {
|
||||
if e.kind() != ErrorKind::NotFound {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Config;
|
||||
|
||||
#[test]
|
||||
fn test_config_set() {
|
||||
let mut config = Config::default();
|
||||
config.set().verbose(false);
|
||||
assert_eq!(config.verbose(), false);
|
||||
config.set().verbose(true);
|
||||
assert_eq!(config.verbose(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_used_to_toml() {
|
||||
let config = Config::default();
|
||||
|
||||
let merge_derives = config.merge_derives();
|
||||
let skip_children = config.skip_children();
|
||||
|
||||
let used_options = config.used_options();
|
||||
let toml = used_options.to_toml().unwrap();
|
||||
assert_eq!(
|
||||
toml,
|
||||
format!(
|
||||
"merge_derives = {}\nskip_children = {}\n",
|
||||
merge_derives, skip_children,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_was_set() {
|
||||
let config = Config::from_toml("hard_tabs = true").unwrap();
|
||||
|
||||
assert_eq!(config.was_set().hard_tabs(), true);
|
||||
assert_eq!(config.was_set().verbose(), false);
|
||||
}
|
||||
|
||||
// FIXME(#2183) these tests cannot be run in parallel because they use env vars
|
||||
// #[test]
|
||||
// fn test_as_not_nightly_channel() {
|
||||
// let mut config = Config::default();
|
||||
// assert_eq!(config.was_set().unstable_features(), false);
|
||||
// config.set().unstable_features(true);
|
||||
// assert_eq!(config.was_set().unstable_features(), false);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_as_nightly_channel() {
|
||||
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
|
||||
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
|
||||
// let mut config = Config::default();
|
||||
// config.set().unstable_features(true);
|
||||
// assert_eq!(config.was_set().unstable_features(), false);
|
||||
// config.set().unstable_features(true);
|
||||
// assert_eq!(config.unstable_features(), true);
|
||||
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_unstable_from_toml() {
|
||||
// let mut config = Config::from_toml("unstable_features = true").unwrap();
|
||||
// assert_eq!(config.was_set().unstable_features(), false);
|
||||
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
|
||||
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
|
||||
// config = Config::from_toml("unstable_features = true").unwrap();
|
||||
// assert_eq!(config.was_set().unstable_features(), true);
|
||||
// assert_eq!(config.unstable_features(), true);
|
||||
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
|
||||
// }
|
||||
}
|
105
rustfmt-config/src/lists.rs
Normal file
105
rustfmt-config/src/lists.rs
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Configuration options related to rewriting a list.
|
||||
|
||||
use IndentStyle;
|
||||
use config_type::ConfigType;
|
||||
|
||||
/// The definitive formatting tactic for lists.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum DefinitiveListTactic {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
Mixed,
|
||||
/// Special case tactic for `format!()`, `write!()` style macros.
|
||||
SpecialMacro(usize),
|
||||
}
|
||||
|
||||
impl DefinitiveListTactic {
|
||||
pub fn ends_with_newline(&self, indent_style: IndentStyle) -> bool {
|
||||
match indent_style {
|
||||
IndentStyle::Block => *self != DefinitiveListTactic::Horizontal,
|
||||
IndentStyle::Visual => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Formatting tactic for lists. This will be cast down to a
|
||||
/// `DefinitiveListTactic` depending on the number and length of the items and
|
||||
/// their comments.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum ListTactic {
|
||||
// One item per row.
|
||||
Vertical,
|
||||
// All items on one row.
|
||||
Horizontal,
|
||||
// Try Horizontal layout, if that fails then vertical.
|
||||
HorizontalVertical,
|
||||
// HorizontalVertical with a soft limit of n characters.
|
||||
LimitedHorizontalVertical(usize),
|
||||
// Pack as many items as possible per row over (possibly) many rows.
|
||||
Mixed,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(ListTactic, Vertical, Horizontal, HorizontalVertical, Mixed);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SeparatorTactic {
|
||||
Always,
|
||||
Never,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(SeparatorTactic, Always, Never, Vertical);
|
||||
|
||||
impl SeparatorTactic {
|
||||
pub fn from_bool(b: bool) -> SeparatorTactic {
|
||||
if b {
|
||||
SeparatorTactic::Always
|
||||
} else {
|
||||
SeparatorTactic::Never
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Where to put separator.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SeparatorPlace {
|
||||
Front,
|
||||
Back,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(SeparatorPlace, Front, Back);
|
||||
|
||||
impl SeparatorPlace {
|
||||
pub fn is_front(&self) -> bool {
|
||||
*self == SeparatorPlace::Front
|
||||
}
|
||||
|
||||
pub fn is_back(&self) -> bool {
|
||||
*self == SeparatorPlace::Back
|
||||
}
|
||||
|
||||
pub fn from_tactic(
|
||||
default: SeparatorPlace,
|
||||
tactic: DefinitiveListTactic,
|
||||
sep: &str,
|
||||
) -> SeparatorPlace {
|
||||
match tactic {
|
||||
DefinitiveListTactic::Vertical => default,
|
||||
_ => if sep == "," {
|
||||
SeparatorPlace::Back
|
||||
} else {
|
||||
default
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
10
rustfmt-config/src/macros.rs
Normal file
10
rustfmt-config/src/macros.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
246
rustfmt-config/src/options.rs
Normal file
246
rustfmt-config/src/options.rs
Normal file
@ -0,0 +1,246 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use config_type::ConfigType;
|
||||
use lists::*;
|
||||
|
||||
/// Macro for deriving implementations of Serialize/Deserialize for enums
|
||||
#[macro_export]
|
||||
macro_rules! impl_enum_serialize_and_deserialize {
|
||||
( $e:ident, $( $x:ident ),* ) => {
|
||||
impl ::serde::ser::Serialize for $e {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ::serde::ser::Serializer
|
||||
{
|
||||
use serde::ser::Error;
|
||||
|
||||
// We don't know whether the user of the macro has given us all options.
|
||||
#[allow(unreachable_patterns)]
|
||||
match *self {
|
||||
$(
|
||||
$e::$x => serializer.serialize_str(stringify!($x)),
|
||||
)*
|
||||
_ => {
|
||||
Err(S::Error::custom(format!("Cannot serialize {:?}", self)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> ::serde::de::Deserialize<'de> for $e {
|
||||
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
||||
where D: ::serde::Deserializer<'de> {
|
||||
use serde::de::{Error, Visitor};
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
struct StringOnly<T>(PhantomData<T>);
|
||||
impl<'de, T> Visitor<'de> for StringOnly<T>
|
||||
where T: ::serde::Deserializer<'de> {
|
||||
type Value = String;
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("string")
|
||||
}
|
||||
fn visit_str<E>(self, value: &str) -> Result<String, E> {
|
||||
Ok(String::from(value))
|
||||
}
|
||||
}
|
||||
let s = d.deserialize_string(StringOnly::<D>(PhantomData))?;
|
||||
$(
|
||||
if stringify!($x).eq_ignore_ascii_case(&s) {
|
||||
return Ok($e::$x);
|
||||
}
|
||||
)*
|
||||
static ALLOWED: &'static[&str] = &[$(stringify!($x),)*];
|
||||
Err(D::Error::unknown_variant(&s, ALLOWED))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::str::FromStr for $e {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
$(
|
||||
if stringify!($x).eq_ignore_ascii_case(s) {
|
||||
return Ok($e::$x);
|
||||
}
|
||||
)*
|
||||
Err("Bad variant")
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigType for $e {
|
||||
fn doc_hint() -> String {
|
||||
let mut variants = Vec::new();
|
||||
$(
|
||||
variants.push(stringify!($x));
|
||||
)*
|
||||
format!("[{}]", variants.join("|"))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! configuration_option_enum{
|
||||
($e:ident: $( $x:ident ),+ $(,)*) => {
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum $e {
|
||||
$( $x ),+
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!($e, $( $x ),+);
|
||||
}
|
||||
}
|
||||
|
||||
configuration_option_enum! { NewlineStyle:
|
||||
Windows, // \r\n
|
||||
Unix, // \n
|
||||
Native, // \r\n in Windows, \n on other platforms
|
||||
}
|
||||
|
||||
configuration_option_enum! { BraceStyle:
|
||||
AlwaysNextLine,
|
||||
PreferSameLine,
|
||||
// Prefer same line except where there is a where clause, in which case force
|
||||
// the brace to the next line.
|
||||
SameLineWhere,
|
||||
}
|
||||
|
||||
configuration_option_enum! { ControlBraceStyle:
|
||||
// K&R style, Rust community default
|
||||
AlwaysSameLine,
|
||||
// Stroustrup style
|
||||
ClosingNextLine,
|
||||
// Allman style
|
||||
AlwaysNextLine,
|
||||
}
|
||||
|
||||
configuration_option_enum! { IndentStyle:
|
||||
// First line on the same line as the opening brace, all lines aligned with
|
||||
// the first line.
|
||||
Visual,
|
||||
// First line is on a new line and all lines align with block indent.
|
||||
Block,
|
||||
}
|
||||
|
||||
configuration_option_enum! { Density:
|
||||
// Fit as much on one line as possible.
|
||||
Compressed,
|
||||
// Use more lines.
|
||||
Tall,
|
||||
// Place every item on a separate line.
|
||||
Vertical,
|
||||
}
|
||||
|
||||
configuration_option_enum! { TypeDensity:
|
||||
// No spaces around "=" and "+"
|
||||
Compressed,
|
||||
// Spaces around " = " and " + "
|
||||
Wide,
|
||||
}
|
||||
|
||||
impl Density {
|
||||
pub fn to_list_tactic(self) -> ListTactic {
|
||||
match self {
|
||||
Density::Compressed => ListTactic::Mixed,
|
||||
Density::Tall => ListTactic::HorizontalVertical,
|
||||
Density::Vertical => ListTactic::Vertical,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configuration_option_enum! { ReportTactic:
|
||||
Always,
|
||||
Unnumbered,
|
||||
Never,
|
||||
}
|
||||
|
||||
configuration_option_enum! { WriteMode:
|
||||
// Backs the original file up and overwrites the original.
|
||||
Replace,
|
||||
// Overwrites original file without backup.
|
||||
Overwrite,
|
||||
// Writes the output to stdout.
|
||||
Display,
|
||||
// Writes the diff to stdout.
|
||||
Diff,
|
||||
// Displays how much of the input file was processed
|
||||
Coverage,
|
||||
// Unfancy stdout
|
||||
Plain,
|
||||
// Outputs a checkstyle XML file.
|
||||
Checkstyle,
|
||||
// Output the changed lines
|
||||
Modified,
|
||||
}
|
||||
|
||||
configuration_option_enum! { Color:
|
||||
// Always use color, whether it is a piped or terminal output
|
||||
Always,
|
||||
// Never use color
|
||||
Never,
|
||||
// Automatically use color, if supported by terminal
|
||||
Auto,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct WidthHeuristics {
|
||||
// Maximum width of the args of a function call before falling back
|
||||
// to vertical formatting.
|
||||
pub fn_call_width: usize,
|
||||
// Maximum width in the body of a struct lit before falling back to
|
||||
// vertical formatting.
|
||||
pub struct_lit_width: usize,
|
||||
// Maximum width in the body of a struct variant before falling back
|
||||
// to vertical formatting.
|
||||
pub struct_variant_width: usize,
|
||||
// Maximum width of an array literal before falling back to vertical
|
||||
// formatting.
|
||||
pub array_width: usize,
|
||||
// Maximum length of a chain to fit on a single line.
|
||||
pub chain_width: usize,
|
||||
// Maximum line length for single line if-else expressions. A value
|
||||
// of zero means always break if-else expressions.
|
||||
pub single_line_if_else_max_width: usize,
|
||||
}
|
||||
|
||||
impl WidthHeuristics {
|
||||
// Using this WidthHeuristics means we ignore heuristics.
|
||||
pub fn null() -> WidthHeuristics {
|
||||
WidthHeuristics {
|
||||
fn_call_width: usize::max_value(),
|
||||
struct_lit_width: 0,
|
||||
struct_variant_width: 0,
|
||||
array_width: usize::max_value(),
|
||||
chain_width: usize::max_value(),
|
||||
single_line_if_else_max_width: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WidthHeuristics {
|
||||
fn default() -> WidthHeuristics {
|
||||
WidthHeuristics {
|
||||
fn_call_width: 60,
|
||||
struct_lit_width: 18,
|
||||
struct_variant_width: 35,
|
||||
array_width: 60,
|
||||
chain_width: 60,
|
||||
single_line_if_else_max_width: 50,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::str::FromStr for WidthHeuristics {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Err("WidthHeuristics is not parsable")
|
||||
}
|
||||
}
|
@ -1,3 +1,13 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use std::default::Default;
|
||||
|
33
rustfmt-core/Cargo.toml
Normal file
33
rustfmt-core/Cargo.toml
Normal file
@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "rustfmt-core"
|
||||
version = "0.4.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
|
||||
description = "A core library of rustfmt"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
categories = ["development-tools"]
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
derive-new = "0.5"
|
||||
diff = "0.1"
|
||||
log = "0.3"
|
||||
regex = "0.2"
|
||||
rustc-ap-syntax = "29.0.0"
|
||||
rustc-ap-rustc_errors = "29.0.0"
|
||||
rustfmt-config = { path = "../rustfmt-config" }
|
||||
term = "0.4"
|
||||
unicode-segmentation = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.0.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.11"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
kernel32-sys = "0.2.2"
|
||||
winapi = "0.2.7"
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::{ast, ptr};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::classify;
|
||||
@ -15,8 +16,7 @@ use syntax::parse::classify;
|
||||
use codemap::SpanUtils;
|
||||
use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr};
|
||||
use items::{span_hi_for_arg, span_lo_for_arg};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
|
||||
ListTactic, Separator, SeparatorPlace, SeparatorTactic};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::Shape;
|
||||
use utils::{last_line_width, left_most_sub_expr, stmt_expr};
|
||||
@ -33,6 +33,7 @@ use utils::{last_line_width, left_most_sub_expr, stmt_expr};
|
||||
|
||||
pub fn rewrite_closure(
|
||||
capture: ast::CaptureBy,
|
||||
movability: ast::Movability,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Expr,
|
||||
span: Span,
|
||||
@ -42,7 +43,7 @@ pub fn rewrite_closure(
|
||||
debug!("rewrite_closure {:?}", body);
|
||||
|
||||
let (prefix, extra_offset) =
|
||||
rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
|
||||
rewrite_closure_fn_decl(capture, movability, fn_decl, body, span, context, shape)?;
|
||||
// 1 = space between `|...|` and body.
|
||||
let body_shape = shape.offset_left(extra_offset)?;
|
||||
|
||||
@ -194,6 +195,7 @@ fn rewrite_closure_block(
|
||||
// Return type is (prefix, extra_offset)
|
||||
fn rewrite_closure_fn_decl(
|
||||
capture: ast::CaptureBy,
|
||||
movability: ast::Movability,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Expr,
|
||||
span: Span,
|
||||
@ -205,9 +207,17 @@ fn rewrite_closure_fn_decl(
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let immovable = if movability == ast::Movability::Static {
|
||||
"static "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
// 4 = "|| {".len(), which is overconservative when the closure consists of
|
||||
// a single expression.
|
||||
let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;
|
||||
let nested_shape = shape
|
||||
.shrink_left(mover.len() + immovable.len())?
|
||||
.sub_width(4)?;
|
||||
|
||||
// 1 = |
|
||||
let argument_offset = nested_shape.indent + 1;
|
||||
@ -244,7 +254,7 @@ fn rewrite_closure_fn_decl(
|
||||
};
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
separator_place: SeparatorPlace::Back,
|
||||
@ -254,7 +264,7 @@ fn rewrite_closure_fn_decl(
|
||||
config: context.config,
|
||||
};
|
||||
let list_str = write_list(&item_vec, &fmt)?;
|
||||
let mut prefix = format!("{}|{}|", mover, list_str);
|
||||
let mut prefix = format!("{}{}|{}|", immovable, mover, list_str);
|
||||
|
||||
if !ret_str.is_empty() {
|
||||
if prefix.contains('\n') {
|
||||
@ -278,7 +288,7 @@ pub fn rewrite_last_closure(
|
||||
expr: &ast::Expr,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
|
||||
if let ast::ExprKind::Closure(capture, movability, ref fn_decl, ref body, _) = expr.node {
|
||||
let body = match body.node {
|
||||
ast::ExprKind::Block(ref block)
|
||||
if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
|
||||
@ -287,8 +297,15 @@ pub fn rewrite_last_closure(
|
||||
}
|
||||
_ => body,
|
||||
};
|
||||
let (prefix, extra_offset) =
|
||||
rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
|
||||
let (prefix, extra_offset) = rewrite_closure_fn_decl(
|
||||
capture,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
expr.span,
|
||||
context,
|
||||
shape,
|
||||
)?;
|
||||
// If the closure goes multi line before its body, do not overflow the closure.
|
||||
if prefix.contains('\n') {
|
||||
return None;
|
@ -11,25 +11,11 @@
|
||||
//! This module contains utilities that work with the `CodeMap` from `libsyntax` / `syntex_syntax`.
|
||||
//! This includes extension traits and methods for looking up spans and line ranges for AST nodes.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use syntax::codemap::{BytePos, CodeMap, FileMap, FileName, Span};
|
||||
use config::file_lines::LineRange;
|
||||
use syntax::codemap::{BytePos, CodeMap, Span};
|
||||
|
||||
use comment::FindUncommented;
|
||||
|
||||
/// A range of lines in a file, inclusive of both ends.
|
||||
pub struct LineRange {
|
||||
pub file: Rc<FileMap>,
|
||||
pub lo: usize,
|
||||
pub hi: usize,
|
||||
}
|
||||
|
||||
impl LineRange {
|
||||
pub fn file_name(&self) -> &FileName {
|
||||
&self.file.name
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpanUtils {
|
||||
fn span_after(&self, original: Span, needle: &str) -> BytePos;
|
||||
fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
|
||||
@ -48,8 +34,8 @@ pub trait LineRangeUtils {
|
||||
|
||||
impl SpanUtils for CodeMap {
|
||||
fn span_after(&self, original: Span, needle: &str) -> BytePos {
|
||||
let snippet = self.span_to_snippet(original).unwrap();
|
||||
let offset = snippet.find_uncommented(needle).unwrap() + needle.len();
|
||||
let snippet = self.span_to_snippet(original).expect("Bad snippet");
|
||||
let offset = snippet.find_uncommented(needle).expect("Bad offset") + needle.len();
|
||||
|
||||
original.lo() + BytePos(offset as u32)
|
||||
}
|
@ -134,6 +134,11 @@ fn comment_style(orig: &str, normalize_comments: bool) -> CommentStyle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Combine `prev_str` and `next_str` into a single `String`. `span` may contain
|
||||
/// comments between two strings. If there are such comments, then that will be
|
||||
/// recovered. If `allow_extend` is true and there is no comment between the two
|
||||
/// strings, then they will be put on a single line as long as doing so does not
|
||||
/// exceed max width.
|
||||
pub fn combine_strs_with_missing_comments(
|
||||
context: &RewriteContext,
|
||||
prev_str: &str,
|
||||
@ -285,11 +290,11 @@ fn rewrite_comment_inner(
|
||||
let mut fmt = StringFormat {
|
||||
opener: "",
|
||||
closer: "",
|
||||
line_start: line_start,
|
||||
line_start,
|
||||
line_end: "",
|
||||
shape: Shape::legacy(max_chars, fmt_indent),
|
||||
trim_end: true,
|
||||
config: config,
|
||||
config,
|
||||
};
|
||||
|
||||
let line_breaks = count_newlines(orig.trim_right());
|
||||
@ -328,7 +333,7 @@ fn rewrite_comment_inner(
|
||||
while let Some(line) = iter.next() {
|
||||
result.push_str(line);
|
||||
result.push_str(match iter.peek() {
|
||||
Some(ref next_line) if next_line.is_empty() => comment_line_separator.trim_right(),
|
||||
Some(next_line) if next_line.is_empty() => comment_line_separator.trim_right(),
|
||||
Some(..) => &comment_line_separator,
|
||||
None => "",
|
||||
});
|
||||
@ -895,7 +900,7 @@ pub struct CommentCodeSlices<'a> {
|
||||
impl<'a> CommentCodeSlices<'a> {
|
||||
pub fn new(slice: &'a str) -> CommentCodeSlices<'a> {
|
||||
CommentCodeSlices {
|
||||
slice: slice,
|
||||
slice,
|
||||
last_slice_kind: CodeCharKind::Comment,
|
||||
last_slice_end: 0,
|
||||
}
|
||||
@ -1019,7 +1024,7 @@ impl<'a> CommentReducer<'a> {
|
||||
let is_block = comment.starts_with("/*");
|
||||
let comment = remove_comment_header(comment);
|
||||
CommentReducer {
|
||||
is_block: is_block,
|
||||
is_block,
|
||||
at_start_line: false, // There are no supplementary '*' on the first line
|
||||
iter: comment.chars(),
|
||||
}
|
@ -12,6 +12,7 @@ use std::borrow::Cow;
|
||||
use std::cmp::min;
|
||||
use std::iter::repeat;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::{ast, ptr};
|
||||
use syntax::codemap::{BytePos, CodeMap, Span};
|
||||
|
||||
@ -22,8 +23,7 @@ use comment::{combine_strs_with_missing_comments, contains_comment, recover_comm
|
||||
rewrite_comment, rewrite_missing_comment, FindUncommented};
|
||||
use config::{Config, ControlBraceStyle, IndentStyle};
|
||||
use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting,
|
||||
struct_lit_shape, struct_lit_tactic, write_list, DefinitiveListTactic, ListFormatting,
|
||||
ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
|
||||
struct_lit_shape, struct_lit_tactic, write_list, ListFormatting, ListItem, Separator};
|
||||
use macros::{rewrite_macro, MacroArg, MacroPosition};
|
||||
use patterns::{can_be_overflowed_pat, TuplePatField};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
@ -135,16 +135,16 @@ pub fn format_expr(
|
||||
ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
|
||||
rewrite_assignment(context, lhs, rhs, Some(op), shape)
|
||||
}
|
||||
ast::ExprKind::Continue(ref opt_ident) => {
|
||||
let id_str = match *opt_ident {
|
||||
Some(ident) => format!(" {}", ident.node),
|
||||
ast::ExprKind::Continue(ref opt_label) => {
|
||||
let id_str = match *opt_label {
|
||||
Some(label) => format!(" {}", label.ident),
|
||||
None => String::new(),
|
||||
};
|
||||
Some(format!("continue{}", id_str))
|
||||
}
|
||||
ast::ExprKind::Break(ref opt_ident, ref opt_expr) => {
|
||||
let id_str = match *opt_ident {
|
||||
Some(ident) => format!(" {}", ident.node),
|
||||
ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
|
||||
let id_str = match *opt_label {
|
||||
Some(label) => format!(" {}", label.ident),
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
@ -159,8 +159,16 @@ pub fn format_expr(
|
||||
} else {
|
||||
Some("yield".to_string())
|
||||
},
|
||||
ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
|
||||
closures::rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
|
||||
ast::ExprKind::Closure(capture, movability, ref fn_decl, ref body, _) => {
|
||||
closures::rewrite_closure(
|
||||
capture,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
expr.span,
|
||||
context,
|
||||
shape,
|
||||
)
|
||||
}
|
||||
ast::ExprKind::Try(..)
|
||||
| ast::ExprKind::Field(..)
|
||||
@ -441,7 +449,7 @@ pub fn rewrite_array<T: Rewrite + Spanned + ToExpr>(
|
||||
let ends_with_newline = tactic.ends_with_newline(context.config.indent_style());
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if trailing_comma {
|
||||
SeparatorTactic::Always
|
||||
@ -462,7 +470,7 @@ pub fn rewrite_array<T: Rewrite + Spanned + ToExpr>(
|
||||
},
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: nested_shape,
|
||||
ends_with_newline: ends_with_newline,
|
||||
ends_with_newline,
|
||||
preserve_newline: false,
|
||||
config: context.config,
|
||||
};
|
||||
@ -718,7 +726,7 @@ struct ControlFlow<'a> {
|
||||
cond: Option<&'a ast::Expr>,
|
||||
block: &'a ast::Block,
|
||||
else_block: Option<&'a ast::Expr>,
|
||||
label: Option<ast::SpannedIdent>,
|
||||
label: Option<ast::Label>,
|
||||
pat: Option<&'a ast::Pat>,
|
||||
keyword: &'a str,
|
||||
matcher: &'a str,
|
||||
@ -779,39 +787,35 @@ impl<'a> ControlFlow<'a> {
|
||||
) -> ControlFlow<'a> {
|
||||
ControlFlow {
|
||||
cond: Some(cond),
|
||||
block: block,
|
||||
else_block: else_block,
|
||||
block,
|
||||
else_block,
|
||||
label: None,
|
||||
pat: pat,
|
||||
pat,
|
||||
keyword: "if",
|
||||
matcher: match pat {
|
||||
Some(..) => "let",
|
||||
None => "",
|
||||
},
|
||||
connector: " =",
|
||||
allow_single_line: allow_single_line,
|
||||
nested_if: nested_if,
|
||||
span: span,
|
||||
allow_single_line,
|
||||
nested_if,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_loop(
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::SpannedIdent>,
|
||||
span: Span,
|
||||
) -> ControlFlow<'a> {
|
||||
fn new_loop(block: &'a ast::Block, label: Option<ast::Label>, span: Span) -> ControlFlow<'a> {
|
||||
ControlFlow {
|
||||
cond: None,
|
||||
block: block,
|
||||
block,
|
||||
else_block: None,
|
||||
label: label,
|
||||
label,
|
||||
pat: None,
|
||||
keyword: "loop",
|
||||
matcher: "",
|
||||
connector: "",
|
||||
allow_single_line: false,
|
||||
nested_if: false,
|
||||
span: span,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -819,15 +823,15 @@ impl<'a> ControlFlow<'a> {
|
||||
pat: Option<&'a ast::Pat>,
|
||||
cond: &'a ast::Expr,
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::SpannedIdent>,
|
||||
label: Option<ast::Label>,
|
||||
span: Span,
|
||||
) -> ControlFlow<'a> {
|
||||
ControlFlow {
|
||||
cond: Some(cond),
|
||||
block: block,
|
||||
block,
|
||||
else_block: None,
|
||||
label: label,
|
||||
pat: pat,
|
||||
label,
|
||||
pat,
|
||||
keyword: "while",
|
||||
matcher: match pat {
|
||||
Some(..) => "let",
|
||||
@ -836,7 +840,7 @@ impl<'a> ControlFlow<'a> {
|
||||
connector: " =",
|
||||
allow_single_line: false,
|
||||
nested_if: false,
|
||||
span: span,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,21 +848,21 @@ impl<'a> ControlFlow<'a> {
|
||||
pat: &'a ast::Pat,
|
||||
cond: &'a ast::Expr,
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::SpannedIdent>,
|
||||
label: Option<ast::Label>,
|
||||
span: Span,
|
||||
) -> ControlFlow<'a> {
|
||||
ControlFlow {
|
||||
cond: Some(cond),
|
||||
block: block,
|
||||
block,
|
||||
else_block: None,
|
||||
label: label,
|
||||
label,
|
||||
pat: Some(pat),
|
||||
keyword: "for",
|
||||
matcher: "",
|
||||
connector: " in",
|
||||
allow_single_line: false,
|
||||
nested_if: false,
|
||||
span: span,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1166,9 +1170,9 @@ impl<'a> Rewrite for ControlFlow<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_label(label: Option<ast::SpannedIdent>) -> Cow<'static, str> {
|
||||
match label {
|
||||
Some(ident) => Cow::from(format!("{}: ", ident.node)),
|
||||
fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
|
||||
match opt_label {
|
||||
Some(label) => Cow::from(format!("{}: ", label.ident)),
|
||||
None => Cow::from(""),
|
||||
}
|
||||
}
|
||||
@ -1484,7 +1488,7 @@ fn rewrite_match_pattern(
|
||||
)
|
||||
};
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: " |",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
separator_place: context.config.binop_separator(),
|
||||
@ -1988,7 +1992,7 @@ where
|
||||
);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if force_trailing_comma {
|
||||
SeparatorTactic::Always
|
||||
@ -2565,9 +2569,13 @@ pub fn rewrite_field(
|
||||
if contains_skip(&field.attrs) {
|
||||
return Some(context.snippet(field.span()).to_owned());
|
||||
}
|
||||
let name = &field.ident.node.to_string();
|
||||
let mut attrs_str = field.attrs.rewrite(context, shape)?;
|
||||
if !attrs_str.is_empty() {
|
||||
attrs_str.push_str(&format!("\n{}", shape.indent.to_string(context.config)));
|
||||
};
|
||||
let name = field.ident.node.to_string();
|
||||
if field.is_shorthand {
|
||||
Some(name.to_string())
|
||||
Some(attrs_str + &name)
|
||||
} else {
|
||||
let mut separator = String::from(struct_lit_field_separator(context.config));
|
||||
for _ in 0..prefix_max_width.checked_sub(name.len()).unwrap_or(0) {
|
||||
@ -2577,12 +2585,10 @@ pub fn rewrite_field(
|
||||
let expr_shape = shape.offset_left(overhead)?;
|
||||
let expr = field.expr.rewrite(context, expr_shape);
|
||||
|
||||
let mut attrs_str = field.attrs.rewrite(context, shape)?;
|
||||
if !attrs_str.is_empty() {
|
||||
attrs_str.push_str(&format!("\n{}", shape.indent.to_string(context.config)));
|
||||
};
|
||||
|
||||
match expr {
|
||||
Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => {
|
||||
Some(attrs_str + &name)
|
||||
}
|
||||
Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
|
||||
None => {
|
||||
let expr_offset = shape.indent.block_indent(context.config);
|
||||
@ -2671,11 +2677,11 @@ where
|
||||
nested_shape.width,
|
||||
);
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: shape,
|
||||
shape,
|
||||
ends_with_newline: false,
|
||||
preserve_newline: false,
|
||||
config: context.config,
|
@ -19,10 +19,7 @@ use config::{Config, NewlineStyle, WriteMode};
|
||||
use rustfmt_diff::{make_diff, output_modified, print_diff, Mismatch};
|
||||
use syntax::codemap::FileName;
|
||||
|
||||
// A map of the files of a crate, with their new content
|
||||
pub type FileMap = Vec<FileRecord>;
|
||||
|
||||
pub type FileRecord = (FileName, String);
|
||||
use FileRecord;
|
||||
|
||||
// Append a newline to the end of each file.
|
||||
pub fn append_newline(s: &mut String) {
|
@ -10,14 +10,14 @@
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
|
||||
use codemap::SpanUtils;
|
||||
use comment::combine_strs_with_missing_comments;
|
||||
use config::IndentStyle;
|
||||
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
|
||||
ListItem, Separator, SeparatorPlace, SeparatorTactic};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::Shape;
|
||||
use spanned::Spanned;
|
||||
@ -105,10 +105,13 @@ fn compare_use_trees(a: &ast::UseTree, b: &ast::UseTree, nested: bool) -> Orderi
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
|
||||
fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Ordering {
|
||||
match (&a.node, &b.node) {
|
||||
(&ast::ItemKind::Mod(..), &ast::ItemKind::Mod(..)) => {
|
||||
a.ident.name.as_str().cmp(&b.ident.name.as_str())
|
||||
}
|
||||
(&ast::ItemKind::Use(ref a_tree), &ast::ItemKind::Use(ref b_tree)) => {
|
||||
Some(compare_use_trees(a_tree, b_tree, false))
|
||||
compare_use_trees(a_tree, b_tree, false)
|
||||
}
|
||||
(&ast::ItemKind::ExternCrate(ref a_name), &ast::ItemKind::ExternCrate(ref b_name)) => {
|
||||
// `extern crate foo as bar;`
|
||||
@ -119,20 +122,19 @@ fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
|
||||
b_name.map_or_else(|| b.ident.name.as_str(), |symbol| symbol.as_str());
|
||||
let result = a_orig_name.cmp(&b_orig_name);
|
||||
if result != Ordering::Equal {
|
||||
return Some(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// `extern crate foo as bar;`
|
||||
// ^^^ Comparing this.
|
||||
let result = match (a_name, b_name) {
|
||||
match (a_name, b_name) {
|
||||
(Some(..), None) => Ordering::Greater,
|
||||
(None, Some(..)) => Ordering::Less,
|
||||
(None, None) => Ordering::Equal,
|
||||
(Some(..), Some(..)) => a.ident.name.cmp(&b.ident.name),
|
||||
};
|
||||
Some(result)
|
||||
(Some(..), Some(..)) => a.ident.name.as_str().cmp(&b.ident.name.as_str()),
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +234,16 @@ fn rewrite_import(
|
||||
}
|
||||
}
|
||||
|
||||
/// Rewrite an inline mod.
|
||||
fn rewrite_mod(item: &ast::Item) -> String {
|
||||
let mut result = String::with_capacity(32);
|
||||
result.push_str(&*format_visibility(&item.vis));
|
||||
result.push_str("mod ");
|
||||
result.push_str(&item.ident.to_string());
|
||||
result.push(';');
|
||||
result
|
||||
}
|
||||
|
||||
fn rewrite_imports(
|
||||
context: &RewriteContext,
|
||||
use_items: &[&ast::Item],
|
||||
@ -246,12 +258,13 @@ fn rewrite_imports(
|
||||
|item| item.span().lo(),
|
||||
|item| item.span().hi(),
|
||||
|item| {
|
||||
let attrs_str = item.attrs.rewrite(context, shape)?;
|
||||
let attrs = ::visitor::filter_inline_attrs(&item.attrs, item.span());
|
||||
let attrs_str = attrs.rewrite(context, shape)?;
|
||||
|
||||
let missed_span = if item.attrs.is_empty() {
|
||||
let missed_span = if attrs.is_empty() {
|
||||
mk_sp(item.span.lo(), item.span.lo())
|
||||
} else {
|
||||
mk_sp(item.attrs.last().unwrap().span.hi(), item.span.lo())
|
||||
mk_sp(attrs.last().unwrap().span.hi(), item.span.lo())
|
||||
};
|
||||
|
||||
let item_str = match item.node {
|
||||
@ -259,6 +272,7 @@ fn rewrite_imports(
|
||||
rewrite_import(context, &item.vis, tree, &item.attrs, shape)?
|
||||
}
|
||||
ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item)?,
|
||||
ast::ItemKind::Mod(..) => rewrite_mod(item),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
@ -276,7 +290,7 @@ fn rewrite_imports(
|
||||
false,
|
||||
);
|
||||
let mut item_pair_vec: Vec<_> = items.zip(use_items.iter()).collect();
|
||||
item_pair_vec.sort_by(|a, b| compare_use_items(a.1, b.1).unwrap());
|
||||
item_pair_vec.sort_by(|a, b| compare_use_items(a.1, b.1));
|
||||
let item_vec: Vec<_> = item_pair_vec.into_iter().map(|pair| pair.0).collect();
|
||||
|
||||
let fmt = ListFormatting {
|
||||
@ -284,7 +298,7 @@ fn rewrite_imports(
|
||||
separator: "",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: shape,
|
||||
shape,
|
||||
ends_with_newline: true,
|
||||
preserve_newline: false,
|
||||
config: context.config,
|
||||
@ -537,7 +551,7 @@ fn rewrite_nested_use_tree(
|
||||
&& tactic != DefinitiveListTactic::Horizontal;
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if ends_with_newline {
|
||||
context.config.trailing_comma()
|
||||
@ -546,7 +560,7 @@ fn rewrite_nested_use_tree(
|
||||
},
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: nested_shape,
|
||||
ends_with_newline: ends_with_newline,
|
||||
ends_with_newline,
|
||||
preserve_newline: true,
|
||||
config: context.config,
|
||||
};
|
@ -14,17 +14,15 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
pub use config::ReportTactic;
|
||||
use config::ReportTactic;
|
||||
|
||||
const TO_DO_CHARS: &[char] = &['t', 'o', 'd', 'o'];
|
||||
const FIX_ME_CHARS: &[char] = &['f', 'i', 'x', 'm', 'e'];
|
||||
|
||||
// Enabled implementation detail is here because it is
|
||||
// irrelevant outside the issues module
|
||||
impl ReportTactic {
|
||||
fn is_enabled(&self) -> bool {
|
||||
*self != ReportTactic::Never
|
||||
}
|
||||
fn is_enabled(report_tactic: ReportTactic) -> bool {
|
||||
report_tactic != ReportTactic::Never
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -90,8 +88,8 @@ impl BadIssueSeeker {
|
||||
todo_idx: 0,
|
||||
fixme_idx: 0,
|
||||
},
|
||||
report_todo: report_todo,
|
||||
report_fixme: report_fixme,
|
||||
report_todo,
|
||||
report_fixme,
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +126,7 @@ impl BadIssueSeeker {
|
||||
|
||||
fn inspect_issue(&mut self, c: char, mut todo_idx: usize, mut fixme_idx: usize) -> Seeking {
|
||||
if let Some(lower_case_c) = c.to_lowercase().next() {
|
||||
if self.report_todo.is_enabled() && lower_case_c == TO_DO_CHARS[todo_idx] {
|
||||
if is_enabled(self.report_todo) && lower_case_c == TO_DO_CHARS[todo_idx] {
|
||||
todo_idx += 1;
|
||||
if todo_idx == TO_DO_CHARS.len() {
|
||||
return Seeking::Number {
|
||||
@ -144,7 +142,7 @@ impl BadIssueSeeker {
|
||||
};
|
||||
}
|
||||
fixme_idx = 0;
|
||||
} else if self.report_fixme.is_enabled() && lower_case_c == FIX_ME_CHARS[fixme_idx] {
|
||||
} else if is_enabled(self.report_fixme) && lower_case_c == FIX_ME_CHARS[fixme_idx] {
|
||||
// Exploit the fact that the character sets of todo and fixme
|
||||
// are disjoint by adding else.
|
||||
fixme_idx += 1;
|
||||
@ -169,8 +167,8 @@ impl BadIssueSeeker {
|
||||
}
|
||||
|
||||
Seeking::Issue {
|
||||
todo_idx: todo_idx,
|
||||
fixme_idx: fixme_idx,
|
||||
todo_idx,
|
||||
fixme_idx,
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,10 +211,7 @@ impl BadIssueSeeker {
|
||||
NumberPart::CloseParen => {}
|
||||
}
|
||||
|
||||
self.state = Seeking::Number {
|
||||
part: part,
|
||||
issue: issue,
|
||||
};
|
||||
self.state = Seeking::Number { part, issue };
|
||||
|
||||
IssueClassification::None
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::min;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::{abi, ast, ptr, symbol};
|
||||
use syntax::ast::{CrateSugar, ImplItem};
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
@ -24,8 +25,7 @@ use comment::{combine_strs_with_missing_comments, contains_comment, recover_comm
|
||||
use config::{BraceStyle, Config, Density, IndentStyle};
|
||||
use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
|
||||
rewrite_call_inner, ExprType};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
|
||||
ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::{Indent, Shape};
|
||||
use spanned::Spanned;
|
||||
@ -138,7 +138,7 @@ impl<'a> Item<'a> {
|
||||
.iter()
|
||||
.map(|i| BodyElement::ForeignItem(i))
|
||||
.collect(),
|
||||
span: span,
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,8 +169,8 @@ impl<'a> FnSig<'a> {
|
||||
vis: ast::Visibility,
|
||||
) -> FnSig<'a> {
|
||||
FnSig {
|
||||
decl: decl,
|
||||
generics: generics,
|
||||
decl,
|
||||
generics,
|
||||
abi: abi::Abi::Rust,
|
||||
constness: ast::Constness::NotConst,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
@ -189,7 +189,7 @@ impl<'a> FnSig<'a> {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
abi: method_sig.abi,
|
||||
decl: &*method_sig.decl,
|
||||
generics: generics,
|
||||
generics,
|
||||
visibility: ast::Visibility::Inherited,
|
||||
}
|
||||
}
|
||||
@ -202,12 +202,12 @@ impl<'a> FnSig<'a> {
|
||||
) -> FnSig<'a> {
|
||||
match *fn_kind {
|
||||
visit::FnKind::ItemFn(_, unsafety, constness, abi, visibility, _) => FnSig {
|
||||
decl: decl,
|
||||
generics: generics,
|
||||
abi: abi,
|
||||
decl,
|
||||
generics,
|
||||
abi,
|
||||
constness: constness.node,
|
||||
defaultness: defualtness,
|
||||
unsafety: unsafety,
|
||||
unsafety,
|
||||
visibility: visibility.clone(),
|
||||
},
|
||||
visit::FnKind::Method(_, method_sig, vis, _) => {
|
||||
@ -504,13 +504,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
items = itemize_list_with(0);
|
||||
}
|
||||
|
||||
let shape = self.shape().sub_width(2).unwrap();
|
||||
let shape = self.shape().sub_width(2)?;
|
||||
let fmt = ListFormatting {
|
||||
tactic: DefinitiveListTactic::Vertical,
|
||||
separator: ",",
|
||||
trailing_separator: self.config.trailing_comma(),
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: shape,
|
||||
shape,
|
||||
ends_with_newline: true,
|
||||
preserve_newline: true,
|
||||
config: self.config,
|
||||
@ -558,14 +558,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
combine_strs_with_missing_comments(
|
||||
&context,
|
||||
&attrs_str,
|
||||
&variant_body,
|
||||
span,
|
||||
shape,
|
||||
is_attributes_extendable(&attrs_str),
|
||||
)
|
||||
combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -895,10 +888,10 @@ impl<'a> StructParts<'a> {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
StructParts {
|
||||
prefix: prefix,
|
||||
prefix,
|
||||
ident: item.ident,
|
||||
vis: &item.vis,
|
||||
def: def,
|
||||
def,
|
||||
generics: Some(generics),
|
||||
span: item.span,
|
||||
}
|
||||
@ -1509,11 +1502,11 @@ impl<'a> StaticParts<'a> {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
StaticParts {
|
||||
prefix: prefix,
|
||||
prefix,
|
||||
vis: &item.vis,
|
||||
ident: item.ident,
|
||||
ty: ty,
|
||||
mutability: mutability,
|
||||
ty,
|
||||
mutability,
|
||||
expr_opt: Some(expr),
|
||||
defaultness: None,
|
||||
span: item.span,
|
||||
@ -1529,7 +1522,7 @@ impl<'a> StaticParts<'a> {
|
||||
prefix: "const",
|
||||
vis: &ast::Visibility::Inherited,
|
||||
ident: ti.ident,
|
||||
ty: ty,
|
||||
ty,
|
||||
mutability: ast::Mutability::Immutable,
|
||||
expr_opt: expr_opt.as_ref(),
|
||||
defaultness: None,
|
||||
@ -1546,7 +1539,7 @@ impl<'a> StaticParts<'a> {
|
||||
prefix: "const",
|
||||
vis: &ii.vis,
|
||||
ident: ii.ident,
|
||||
ty: ty,
|
||||
ty,
|
||||
mutability: ast::Mutability::Immutable,
|
||||
expr_opt: Some(expr),
|
||||
defaultness: Some(ii.defaultness),
|
||||
@ -1818,7 +1811,7 @@ fn rewrite_fn_base(
|
||||
let one_line_budget = context.budget(used_width + overhead);
|
||||
let shape = Shape {
|
||||
width: one_line_budget,
|
||||
indent: indent,
|
||||
indent,
|
||||
offset: used_width,
|
||||
};
|
||||
let fd = fn_sig.decl;
|
||||
@ -2085,8 +2078,8 @@ struct WhereClauseOption {
|
||||
impl WhereClauseOption {
|
||||
pub fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption {
|
||||
WhereClauseOption {
|
||||
suppress_comma: suppress_comma,
|
||||
snuggle: snuggle,
|
||||
suppress_comma,
|
||||
snuggle,
|
||||
compress_where: false,
|
||||
}
|
||||
}
|
||||
@ -2233,7 +2226,7 @@ fn rewrite_args(
|
||||
debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if variadic {
|
||||
SeparatorTactic::Never
|
||||
@ -2404,7 +2397,7 @@ where
|
||||
one_line_budget,
|
||||
);
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if context.config.indent_style() == IndentStyle::Visual {
|
||||
SeparatorTactic::Never
|
||||
@ -2412,7 +2405,7 @@ where
|
||||
context.config.trailing_comma()
|
||||
},
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: shape,
|
||||
shape,
|
||||
ends_with_newline: tactic.ends_with_newline(context.config.indent_style()),
|
||||
preserve_newline: true,
|
||||
config: context.config,
|
||||
@ -2637,7 +2630,7 @@ fn rewrite_where_clause(
|
||||
}
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: comma_tactic,
|
||||
separator_place: SeparatorPlace::Back,
|
@ -8,8 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(decl_macro)]
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(type_ascription)]
|
||||
|
||||
#[macro_use]
|
||||
@ -19,10 +19,7 @@ extern crate diff;
|
||||
extern crate log;
|
||||
extern crate regex;
|
||||
extern crate rustc_errors as errors;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate rustfmt_config as config;
|
||||
extern crate syntax;
|
||||
extern crate term;
|
||||
extern crate unicode_segmentation;
|
||||
@ -44,43 +41,44 @@ use syntax::parse::{self, ParseSess};
|
||||
|
||||
use checkstyle::{output_footer, output_header};
|
||||
use comment::{CharClasses, FullCodeCharKind};
|
||||
pub use config::Config;
|
||||
use filemap::FileMap;
|
||||
use issues::{BadIssueSeeker, Issue};
|
||||
use shape::Indent;
|
||||
use utils::use_colored_tty;
|
||||
use visitor::{FmtVisitor, SnippetProvider};
|
||||
|
||||
pub use self::summary::Summary;
|
||||
pub use config::Config;
|
||||
pub use config::summary::Summary;
|
||||
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
mod shape;
|
||||
mod spanned;
|
||||
pub mod config;
|
||||
pub mod codemap;
|
||||
pub mod filemap;
|
||||
pub mod file_lines;
|
||||
pub mod visitor;
|
||||
mod chains;
|
||||
mod checkstyle;
|
||||
mod closures;
|
||||
mod items;
|
||||
mod missed_spans;
|
||||
mod lists;
|
||||
mod types;
|
||||
pub mod codemap;
|
||||
mod comment;
|
||||
mod expr;
|
||||
pub mod filemap;
|
||||
mod imports;
|
||||
mod issues;
|
||||
mod rewrite;
|
||||
mod string;
|
||||
mod comment;
|
||||
pub mod modules;
|
||||
pub mod rustfmt_diff;
|
||||
mod chains;
|
||||
mod items;
|
||||
mod lists;
|
||||
mod macros;
|
||||
mod missed_spans;
|
||||
pub mod modules;
|
||||
mod patterns;
|
||||
mod summary;
|
||||
mod rewrite;
|
||||
pub mod rustfmt_diff;
|
||||
mod shape;
|
||||
mod spanned;
|
||||
mod string;
|
||||
mod types;
|
||||
mod vertical;
|
||||
pub mod visitor;
|
||||
|
||||
// A map of the files of a crate, with their new content
|
||||
pub type FileMap = Vec<FileRecord>;
|
||||
|
||||
pub type FileRecord = (FileName, String);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ErrorKind {
|
||||
@ -165,7 +163,7 @@ impl FormatReport {
|
||||
self.file_error_map
|
||||
.iter()
|
||||
.map(|(_, errors)| errors.len())
|
||||
.fold(0, |acc, x| acc + x)
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn has_warnings(&self) -> bool {
|
||||
@ -448,7 +446,7 @@ fn format_lines(
|
||||
line: cur_line,
|
||||
kind: error_kind,
|
||||
is_comment: kind.is_comment(),
|
||||
is_string: is_string,
|
||||
is_string,
|
||||
line_buffer: line_buffer.clone(),
|
||||
});
|
||||
}
|
||||
@ -463,7 +461,7 @@ fn format_lines(
|
||||
is_string = false;
|
||||
} else {
|
||||
newline_count = 0;
|
||||
line_len += 1;
|
||||
line_len += if c == '\t' { config.tab_spaces() } else { 1 };
|
||||
if c.is_whitespace() {
|
||||
if last_wspace.is_none() {
|
||||
last_wspace = Some(b);
|
||||
@ -570,7 +568,12 @@ pub fn format_code_block(code_snippet: &str, config: &Config) -> Option<String>
|
||||
let indent_str =
|
||||
Indent::from_width(config, config.tab_spaces()).to_string(config);
|
||||
if line.starts_with(indent_str.as_ref()) {
|
||||
&line[config.tab_spaces()..]
|
||||
let offset = if config.hard_tabs() {
|
||||
1
|
||||
} else {
|
||||
config.tab_spaces()
|
||||
};
|
||||
&line[offset..]
|
||||
} else {
|
||||
line
|
||||
}
|
||||
@ -605,10 +608,17 @@ pub fn format_input<T: Write>(
|
||||
Box::new(Vec::new()),
|
||||
Some(codemap.clone()),
|
||||
false,
|
||||
false,
|
||||
));
|
||||
Handler::with_emitter(true, false, silent_emitter)
|
||||
} else {
|
||||
Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()))
|
||||
let supports_color = term::stderr().map_or(false, |term| term.supports_color());
|
||||
let color_cfg = if supports_color {
|
||||
ColorConfig::Auto
|
||||
} else {
|
||||
ColorConfig::Never
|
||||
};
|
||||
Handler::with_tty_emitter(color_cfg, true, false, Some(codemap.clone()))
|
||||
};
|
||||
let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
|
||||
|
||||
@ -639,6 +649,7 @@ pub fn format_input<T: Write>(
|
||||
Box::new(Vec::new()),
|
||||
Some(codemap.clone()),
|
||||
false,
|
||||
false,
|
||||
));
|
||||
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
|
||||
|
@ -8,9 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Format list-like expressions and items.
|
||||
|
||||
use std::cmp;
|
||||
use std::iter::Peekable;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::codemap::{BytePos, CodeMap};
|
||||
|
||||
use comment::{find_comment_end, rewrite_comment, FindUncommented};
|
||||
@ -19,44 +22,6 @@ use rewrite::RewriteContext;
|
||||
use shape::{Indent, Shape};
|
||||
use utils::{count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline};
|
||||
|
||||
/// Formatting tactic for lists. This will be cast down to a
|
||||
/// `DefinitiveListTactic` depending on the number and length of the items and
|
||||
/// their comments.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum ListTactic {
|
||||
// One item per row.
|
||||
Vertical,
|
||||
// All items on one row.
|
||||
Horizontal,
|
||||
// Try Horizontal layout, if that fails then vertical.
|
||||
HorizontalVertical,
|
||||
// HorizontalVertical with a soft limit of n characters.
|
||||
LimitedHorizontalVertical(usize),
|
||||
// Pack as many items as possible per row over (possibly) many rows.
|
||||
Mixed,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(ListTactic, Vertical, Horizontal, HorizontalVertical, Mixed);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SeparatorTactic {
|
||||
Always,
|
||||
Never,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(SeparatorTactic, Always, Never, Vertical);
|
||||
|
||||
impl SeparatorTactic {
|
||||
pub fn from_bool(b: bool) -> SeparatorTactic {
|
||||
if b {
|
||||
SeparatorTactic::Always
|
||||
} else {
|
||||
SeparatorTactic::Never
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ListFormatting<'a> {
|
||||
pub tactic: DefinitiveListTactic,
|
||||
pub separator: &'a str,
|
||||
@ -154,25 +119,6 @@ impl ListItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// The definitive formatting tactic for lists.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum DefinitiveListTactic {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
Mixed,
|
||||
/// Special case tactic for `format!()`, `write!()` style macros.
|
||||
SpecialMacro(usize),
|
||||
}
|
||||
|
||||
impl DefinitiveListTactic {
|
||||
pub fn ends_with_newline(&self, indent_style: IndentStyle) -> bool {
|
||||
match indent_style {
|
||||
IndentStyle::Block => *self != DefinitiveListTactic::Horizontal,
|
||||
IndentStyle::Visual => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of separator for lists.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Separator {
|
||||
@ -191,40 +137,6 @@ impl Separator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where to put separator.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SeparatorPlace {
|
||||
Front,
|
||||
Back,
|
||||
}
|
||||
|
||||
impl_enum_serialize_and_deserialize!(SeparatorPlace, Front, Back);
|
||||
|
||||
impl SeparatorPlace {
|
||||
pub fn is_front(&self) -> bool {
|
||||
*self == SeparatorPlace::Front
|
||||
}
|
||||
|
||||
pub fn is_back(&self) -> bool {
|
||||
*self == SeparatorPlace::Back
|
||||
}
|
||||
|
||||
pub fn from_tactic(
|
||||
default: SeparatorPlace,
|
||||
tactic: DefinitiveListTactic,
|
||||
sep: &str,
|
||||
) -> SeparatorPlace {
|
||||
match tactic {
|
||||
DefinitiveListTactic::Vertical => default,
|
||||
_ => if sep == "," {
|
||||
SeparatorPlace::Back
|
||||
} else {
|
||||
default
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definitive_tactic<I, T>(
|
||||
items: I,
|
||||
tactic: ListTactic,
|
||||
@ -690,15 +602,15 @@ where
|
||||
};
|
||||
|
||||
ListItem {
|
||||
pre_comment: pre_comment,
|
||||
pre_comment_style: pre_comment_style,
|
||||
pre_comment,
|
||||
pre_comment_style,
|
||||
item: if self.inner.peek().is_none() && self.leave_last {
|
||||
None
|
||||
} else {
|
||||
(self.get_item_string)(&item)
|
||||
},
|
||||
post_comment: post_comment,
|
||||
new_lines: new_lines,
|
||||
post_comment,
|
||||
new_lines,
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -724,16 +636,16 @@ where
|
||||
F3: Fn(&T) -> Option<String>,
|
||||
{
|
||||
ListItems {
|
||||
codemap: codemap,
|
||||
codemap,
|
||||
inner: inner.peekable(),
|
||||
get_lo: get_lo,
|
||||
get_hi: get_hi,
|
||||
get_item_string: get_item_string,
|
||||
prev_span_end: prev_span_end,
|
||||
next_span_start: next_span_start,
|
||||
terminator: terminator,
|
||||
separator: separator,
|
||||
leave_last: leave_last,
|
||||
get_lo,
|
||||
get_hi,
|
||||
get_item_string,
|
||||
prev_span_end,
|
||||
next_span_start,
|
||||
terminator,
|
||||
separator,
|
||||
leave_last,
|
||||
}
|
||||
}
|
||||
|
||||
@ -841,7 +753,7 @@ pub fn struct_lit_formatting<'a>(
|
||||
let ends_with_newline = context.config.indent_style() != IndentStyle::Visual
|
||||
&& tactic == DefinitiveListTactic::Vertical;
|
||||
ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if force_no_trailing_comma {
|
||||
SeparatorTactic::Never
|
||||
@ -849,8 +761,8 @@ pub fn struct_lit_formatting<'a>(
|
||||
context.config.trailing_comma()
|
||||
},
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: shape,
|
||||
ends_with_newline: ends_with_newline,
|
||||
shape,
|
||||
ends_with_newline,
|
||||
preserve_newline: true,
|
||||
config: context.config,
|
||||
}
|
@ -20,6 +20,8 @@
|
||||
// and those with brackets will be formatted as array literals.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
use syntax::parse::new_parser_from_tts;
|
||||
@ -33,6 +35,7 @@ use syntax::util::ThinVec;
|
||||
use codemap::SpanUtils;
|
||||
use comment::{contains_comment, remove_trailing_white_spaces, FindUncommented};
|
||||
use expr::{rewrite_array, rewrite_call_inner};
|
||||
use lists::{itemize_list, write_list, ListFormatting};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::{Indent, Shape};
|
||||
use utils::{format_visibility, mk_sp};
|
||||
@ -101,7 +104,7 @@ fn parse_macro_arg(parser: &mut Parser) -> Option<MacroArg> {
|
||||
parser.sess.span_diagnostic.reset_err_count();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
parse_macro_arg!(Expr, parse_expr);
|
||||
@ -283,6 +286,7 @@ pub fn rewrite_macro(
|
||||
|
||||
pub fn rewrite_macro_def(
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
indent: Indent,
|
||||
def: &ast::MacroDef,
|
||||
ident: ast::Ident,
|
||||
@ -291,85 +295,67 @@ pub fn rewrite_macro_def(
|
||||
) -> Option<String> {
|
||||
let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
|
||||
|
||||
if def.legacy {
|
||||
return snippet;
|
||||
}
|
||||
|
||||
let mut parser = MacroParser::new(def.stream().into_trees());
|
||||
let mut parsed_def = match parser.parse() {
|
||||
let parsed_def = match parser.parse() {
|
||||
Some(def) => def,
|
||||
None => return snippet,
|
||||
};
|
||||
|
||||
// Only attempt to format function-like macros.
|
||||
if parsed_def.branches.len() != 1 || parsed_def.branches[0].args_paren_kind != DelimToken::Paren
|
||||
{
|
||||
// FIXME(#1539): implement for non-sugared macros.
|
||||
return snippet;
|
||||
}
|
||||
|
||||
let branch = parsed_def.branches.remove(0);
|
||||
let args_str = format_macro_args(branch.args)?;
|
||||
|
||||
// The macro body is the most interesting part. It might end up as various
|
||||
// AST nodes, but also has special variables (e.g, `$foo`) which can't be
|
||||
// parsed as regular Rust code (and note that these can be escaped using
|
||||
// `$$`). We'll try and format like an AST node, but we'll substitute
|
||||
// variables for new names with the same length first.
|
||||
|
||||
let old_body = context.snippet(branch.body).trim();
|
||||
let (body_str, substs) = replace_names(old_body);
|
||||
|
||||
// We'll hack the indent below, take this into account when formatting,
|
||||
let mut config = context.config.clone();
|
||||
let new_width = config.max_width() - indent.block_indent(&config).width();
|
||||
config.set().max_width(new_width);
|
||||
config.set().hide_parse_errors(true);
|
||||
|
||||
// First try to format as items, then as statements.
|
||||
let new_body = match ::format_snippet(&body_str, &config) {
|
||||
Some(new_body) => new_body,
|
||||
None => match ::format_code_block(&body_str, &config) {
|
||||
Some(new_body) => new_body,
|
||||
None => return snippet,
|
||||
},
|
||||
let mut result = if def.legacy {
|
||||
String::from("macro_rules!")
|
||||
} else {
|
||||
format!("{}macro", format_visibility(vis))
|
||||
};
|
||||
|
||||
// Indent the body since it is in a block.
|
||||
let indent_str = indent.block_indent(&config).to_string(&config);
|
||||
let mut new_body = new_body
|
||||
.lines()
|
||||
.map(|l| {
|
||||
if l.is_empty() {
|
||||
l.to_owned()
|
||||
} else {
|
||||
format!("{}{}", indent_str, l)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
result += " ";
|
||||
result += &ident.name.as_str();
|
||||
|
||||
// Undo our replacement of macro variables.
|
||||
// FIXME: this could be *much* more efficient.
|
||||
for (old, new) in substs.iter() {
|
||||
if old_body.find(new).is_some() {
|
||||
debug!(
|
||||
"rewrite_macro_def: bailing matching variable: `{}` in `{}`",
|
||||
new, ident
|
||||
);
|
||||
return snippet;
|
||||
}
|
||||
new_body = new_body.replace(new, old);
|
||||
let multi_branch_style = def.legacy || parsed_def.branches.len() != 1;
|
||||
|
||||
let arm_shape = if multi_branch_style {
|
||||
shape
|
||||
.block_indent(context.config.tab_spaces())
|
||||
.with_max_width(context.config)
|
||||
} else {
|
||||
shape
|
||||
};
|
||||
|
||||
let branch_items = itemize_list(
|
||||
context.codemap,
|
||||
parsed_def.branches.iter(),
|
||||
"}",
|
||||
";",
|
||||
|branch| branch.span.lo(),
|
||||
|branch| branch.span.hi(),
|
||||
|branch| branch.rewrite(context, arm_shape, multi_branch_style),
|
||||
context.codemap.span_after(span, "{"),
|
||||
span.hi(),
|
||||
false,
|
||||
).collect::<Vec<_>>();
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: DefinitiveListTactic::Vertical,
|
||||
separator: if def.legacy { ";" } else { "" },
|
||||
trailing_separator: SeparatorTactic::Always,
|
||||
separator_place: SeparatorPlace::Back,
|
||||
shape: arm_shape,
|
||||
ends_with_newline: true,
|
||||
preserve_newline: true,
|
||||
config: context.config,
|
||||
};
|
||||
|
||||
if multi_branch_style {
|
||||
result += " {\n";
|
||||
result += &arm_shape.indent.to_string(context.config);
|
||||
}
|
||||
|
||||
let result = format!(
|
||||
"{}macro {}({}) {{\n{}\n{}}}",
|
||||
format_visibility(vis),
|
||||
ident,
|
||||
args_str,
|
||||
new_body,
|
||||
indent.to_string(&context.config),
|
||||
);
|
||||
result += write_list(&branch_items, &fmt)?.as_str();
|
||||
|
||||
if multi_branch_style {
|
||||
result += "\n";
|
||||
result += &indent.to_string(context.config);
|
||||
result += "}";
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
@ -377,7 +363,7 @@ pub fn rewrite_macro_def(
|
||||
// Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
|
||||
// aren't causing problems.
|
||||
// This should also work for escaped `$` variables, where we leave earlier `$`s.
|
||||
fn replace_names(input: &str) -> (String, HashMap<String, String>) {
|
||||
fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
|
||||
// Each substitution will require five or six extra bytes.
|
||||
let mut result = String::with_capacity(input.len() + 64);
|
||||
let mut substs = HashMap::new();
|
||||
@ -409,6 +395,9 @@ fn replace_names(input: &str) -> (String, HashMap<String, String>) {
|
||||
|
||||
dollar_count = 0;
|
||||
cur_name = String::new();
|
||||
} else if c == '(' && cur_name.is_empty() {
|
||||
// FIXME: Support macro def with repeat.
|
||||
return None;
|
||||
} else if c.is_alphanumeric() {
|
||||
cur_name.push(c);
|
||||
}
|
||||
@ -433,7 +422,7 @@ fn replace_names(input: &str) -> (String, HashMap<String, String>) {
|
||||
|
||||
debug!("replace_names `{}` {:?}", result, substs);
|
||||
|
||||
(result, substs)
|
||||
Some((result, substs))
|
||||
}
|
||||
|
||||
// This is a bit sketchy. The token rules probably need tweaking, but it works
|
||||
@ -467,13 +456,10 @@ fn format_macro_args(toks: ThinTokenStream) -> Option<String> {
|
||||
insert_space = next_space(&t);
|
||||
}
|
||||
TokenTree::Delimited(_, d) => {
|
||||
let formatted = format_macro_args(d.tts)?;
|
||||
match insert_space {
|
||||
SpaceState::Always => {
|
||||
result.push(' ');
|
||||
}
|
||||
_ => {}
|
||||
if let SpaceState::Always = insert_space {
|
||||
result.push(' ');
|
||||
}
|
||||
let formatted = format_macro_args(d.tts)?;
|
||||
match d.delim {
|
||||
DelimToken::Paren => {
|
||||
result.push_str(&format!("({})", formatted));
|
||||
@ -711,24 +697,34 @@ impl MacroParser {
|
||||
|
||||
// `(` ... `)` `=>` `{` ... `}`
|
||||
fn parse_branch(&mut self) -> Option<MacroBranch> {
|
||||
let (args_paren_kind, args) = match self.toks.next()? {
|
||||
let tok = self.toks.next()?;
|
||||
let (lo, args_paren_kind) = match tok {
|
||||
TokenTree::Token(..) => return None,
|
||||
TokenTree::Delimited(_, ref d) => (d.delim, d.tts.clone().into()),
|
||||
TokenTree::Delimited(sp, ref d) => (sp.lo(), d.delim),
|
||||
};
|
||||
let args = tok.joint().into();
|
||||
match self.toks.next()? {
|
||||
TokenTree::Token(_, Token::FatArrow) => {}
|
||||
_ => return None,
|
||||
}
|
||||
let body = match self.toks.next()? {
|
||||
let (mut hi, body) = match self.toks.next()? {
|
||||
TokenTree::Token(..) => return None,
|
||||
TokenTree::Delimited(sp, _) => {
|
||||
let data = sp.data();
|
||||
Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt)
|
||||
(
|
||||
data.hi,
|
||||
Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt),
|
||||
)
|
||||
}
|
||||
};
|
||||
if let Some(TokenTree::Token(sp, Token::Semi)) = self.toks.look_ahead(0) {
|
||||
self.toks.next();
|
||||
hi = sp.hi();
|
||||
}
|
||||
Some(MacroBranch {
|
||||
args,
|
||||
span: mk_sp(lo, hi),
|
||||
args_paren_kind,
|
||||
args,
|
||||
body,
|
||||
})
|
||||
}
|
||||
@ -742,11 +738,102 @@ struct Macro {
|
||||
// FIXME: it would be more efficient to use references to the token streams
|
||||
// rather than clone them, if we can make the borrowing work out.
|
||||
struct MacroBranch {
|
||||
args: ThinTokenStream,
|
||||
span: Span,
|
||||
args_paren_kind: DelimToken,
|
||||
args: ThinTokenStream,
|
||||
body: Span,
|
||||
}
|
||||
|
||||
impl MacroBranch {
|
||||
fn rewrite(
|
||||
&self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
multi_branch_style: bool,
|
||||
) -> Option<String> {
|
||||
// Only attempt to format function-like macros.
|
||||
if self.args_paren_kind != DelimToken::Paren {
|
||||
// FIXME(#1539): implement for non-sugared macros.
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut result = format_macro_args(self.args.clone())?;
|
||||
|
||||
if multi_branch_style {
|
||||
result += " =>";
|
||||
}
|
||||
|
||||
// The macro body is the most interesting part. It might end up as various
|
||||
// AST nodes, but also has special variables (e.g, `$foo`) which can't be
|
||||
// parsed as regular Rust code (and note that these can be escaped using
|
||||
// `$$`). We'll try and format like an AST node, but we'll substitute
|
||||
// variables for new names with the same length first.
|
||||
|
||||
let old_body = context.snippet(self.body).trim();
|
||||
let (body_str, substs) = replace_names(old_body)?;
|
||||
|
||||
let mut config = context.config.clone();
|
||||
config.set().hide_parse_errors(true);
|
||||
|
||||
result += " {";
|
||||
|
||||
let has_block_body = old_body.starts_with('{');
|
||||
|
||||
let body_indent = if has_block_body {
|
||||
shape.indent
|
||||
} else {
|
||||
// We'll hack the indent below, take this into account when formatting,
|
||||
let body_indent = shape.indent.block_indent(&config);
|
||||
let new_width = config.max_width() - body_indent.width();
|
||||
config.set().max_width(new_width);
|
||||
body_indent
|
||||
};
|
||||
|
||||
// First try to format as items, then as statements.
|
||||
let new_body = match ::format_snippet(&body_str, &config) {
|
||||
Some(new_body) => new_body,
|
||||
None => match ::format_code_block(&body_str, &config) {
|
||||
Some(new_body) => new_body,
|
||||
None => return None,
|
||||
},
|
||||
};
|
||||
|
||||
// Indent the body since it is in a block.
|
||||
let indent_str = body_indent.to_string(&config);
|
||||
let mut new_body = new_body
|
||||
.trim_right()
|
||||
.lines()
|
||||
.fold(String::new(), |mut s, l| {
|
||||
if !l.is_empty() {
|
||||
s += &indent_str;
|
||||
}
|
||||
s + l + "\n"
|
||||
});
|
||||
|
||||
// Undo our replacement of macro variables.
|
||||
// FIXME: this could be *much* more efficient.
|
||||
for (old, new) in &substs {
|
||||
if old_body.find(new).is_some() {
|
||||
debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
|
||||
return None;
|
||||
}
|
||||
new_body = new_body.replace(new, old);
|
||||
}
|
||||
|
||||
if has_block_body {
|
||||
result += new_body.trim();
|
||||
} else if !new_body.is_empty() {
|
||||
result += "\n";
|
||||
result += &new_body;
|
||||
result += &shape.indent.to_string(&config);
|
||||
}
|
||||
|
||||
result += "}";
|
||||
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::ast::{self, BindingMode, FieldPat, Pat, PatKind, RangeEnd, RangeSyntax};
|
||||
use syntax::codemap::{self, BytePos, Span};
|
||||
use syntax::ptr;
|
||||
@ -17,7 +18,7 @@ use comment::FindUncommented;
|
||||
use expr::{can_be_overflowed_expr, rewrite_call_inner, rewrite_pair, rewrite_unary_prefix,
|
||||
wrap_struct_field, PairParts};
|
||||
use lists::{itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
|
||||
struct_lit_tactic, write_list, DefinitiveListTactic, SeparatorPlace, SeparatorTactic};
|
||||
struct_lit_tactic, write_list};
|
||||
use macros::{rewrite_macro, MacroPosition};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::Shape;
|
||||
@ -65,10 +66,15 @@ impl Rewrite for Pat {
|
||||
RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
|
||||
RangeEnd::Excluded => "..",
|
||||
};
|
||||
let infix = if context.config.spaces_around_ranges() {
|
||||
format!(" {} ", infix)
|
||||
} else {
|
||||
infix.to_owned()
|
||||
};
|
||||
rewrite_pair(
|
||||
&**lhs,
|
||||
&**rhs,
|
||||
PairParts::new("", infix, ""),
|
||||
PairParts::new("", &infix, ""),
|
||||
context,
|
||||
shape,
|
||||
SeparatorPlace::Front,
|
@ -36,8 +36,8 @@ pub struct Mismatch {
|
||||
impl Mismatch {
|
||||
fn new(line_number: u32, line_number_orig: u32) -> Mismatch {
|
||||
Mismatch {
|
||||
line_number: line_number,
|
||||
line_number_orig: line_number_orig,
|
||||
line_number,
|
||||
line_number_orig,
|
||||
lines: Vec::new(),
|
||||
}
|
||||
}
|
@ -29,8 +29,8 @@ const INDENT_BUFFER: &str =
|
||||
impl Indent {
|
||||
pub fn new(block_indent: usize, alignment: usize) -> Indent {
|
||||
Indent {
|
||||
block_indent: block_indent,
|
||||
alignment: alignment,
|
||||
block_indent,
|
||||
alignment,
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,8 +161,8 @@ impl Shape {
|
||||
// |<--->| width
|
||||
pub fn legacy(width: usize, indent: Indent) -> Shape {
|
||||
Shape {
|
||||
width: width,
|
||||
indent: indent,
|
||||
width,
|
||||
indent,
|
||||
offset: indent.alignment,
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ impl Shape {
|
||||
pub fn indented(indent: Indent, config: &Config) -> Shape {
|
||||
Shape {
|
||||
width: config.max_width().checked_sub(indent.width()).unwrap_or(0),
|
||||
indent: indent,
|
||||
indent,
|
||||
offset: indent.alignment,
|
||||
}
|
||||
}
|
||||
@ -187,9 +187,9 @@ impl Shape {
|
||||
|
||||
pub fn offset(width: usize, indent: Indent, offset: usize) -> Shape {
|
||||
Shape {
|
||||
width: width,
|
||||
indent: indent,
|
||||
offset: offset,
|
||||
width,
|
||||
indent,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
|
@ -20,32 +20,30 @@ pub trait Spanned {
|
||||
}
|
||||
|
||||
macro_rules! span_with_attrs_lo_hi {
|
||||
($this:ident, $lo:expr, $hi:expr) => {
|
||||
{
|
||||
let attrs = outer_attributes(&$this.attrs);
|
||||
if attrs.is_empty() {
|
||||
mk_sp($lo, $hi)
|
||||
} else {
|
||||
mk_sp(attrs[0].span.lo(), $hi)
|
||||
}
|
||||
($this: ident, $lo: expr, $hi: expr) => {{
|
||||
let attrs = outer_attributes(&$this.attrs);
|
||||
if attrs.is_empty() {
|
||||
mk_sp($lo, $hi)
|
||||
} else {
|
||||
mk_sp(attrs[0].span.lo(), $hi)
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! span_with_attrs {
|
||||
($this:ident) => {
|
||||
($this: ident) => {
|
||||
span_with_attrs_lo_hi!($this, $this.span.lo(), $this.span.hi())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! implement_spanned {
|
||||
($this:ty) => {
|
||||
($this: ty) => {
|
||||
impl Spanned for $this {
|
||||
fn span(&self) -> Span {
|
||||
span_with_attrs!(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Implement `Spanned` for structs with `attrs` field.
|
@ -36,9 +36,9 @@ impl<'a> StringFormat<'a> {
|
||||
closer: "\"",
|
||||
line_start: " ",
|
||||
line_end: "\\",
|
||||
shape: shape,
|
||||
shape,
|
||||
trim_end: false,
|
||||
config: config,
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::ops::Deref;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::ast::{self, FunctionRetTy, Mutability};
|
||||
use syntax::codemap::{self, BytePos, Span};
|
||||
use syntax::print::pprust;
|
||||
@ -20,8 +21,7 @@ use codemap::SpanUtils;
|
||||
use config::{IndentStyle, TypeDensity};
|
||||
use expr::{rewrite_pair, rewrite_tuple, rewrite_unary_prefix, wrap_args_with_parens, PairParts};
|
||||
use items::{format_generics_item_list, generics_shape_from_config};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListTactic, Separator,
|
||||
SeparatorPlace, SeparatorTactic};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
|
||||
use macros::{rewrite_macro, MacroPosition};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::Shape;
|
||||
@ -352,7 +352,7 @@ where
|
||||
);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: if !context.use_block_indent() || variadic {
|
||||
SeparatorTactic::Never
|
@ -178,7 +178,7 @@ pub fn last_line_extendable(s: &str) -> bool {
|
||||
}
|
||||
for c in s.chars().rev() {
|
||||
match c {
|
||||
')' | ']' | '}' | '?' | '>' => continue,
|
||||
'(' | ')' | ']' | '}' | '?' | '>' => continue,
|
||||
'\n' => break,
|
||||
_ if c.is_whitespace() => continue,
|
||||
_ => return false,
|
||||
@ -254,82 +254,6 @@ pub fn count_newlines(input: &str) -> usize {
|
||||
input.chars().filter(|&c| c == '\n').count()
|
||||
}
|
||||
|
||||
// Macro for deriving implementations of Serialize/Deserialize for enums
|
||||
#[macro_export]
|
||||
macro_rules! impl_enum_serialize_and_deserialize {
|
||||
( $e:ident, $( $x:ident ),* ) => {
|
||||
impl ::serde::ser::Serialize for $e {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ::serde::ser::Serializer
|
||||
{
|
||||
use serde::ser::Error;
|
||||
|
||||
// We don't know whether the user of the macro has given us all options.
|
||||
#[allow(unreachable_patterns)]
|
||||
match *self {
|
||||
$(
|
||||
$e::$x => serializer.serialize_str(stringify!($x)),
|
||||
)*
|
||||
_ => {
|
||||
Err(S::Error::custom(format!("Cannot serialize {:?}", self)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> ::serde::de::Deserialize<'de> for $e {
|
||||
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
||||
where D: ::serde::Deserializer<'de> {
|
||||
use serde::de::{Error, Visitor};
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
struct StringOnly<T>(PhantomData<T>);
|
||||
impl<'de, T> Visitor<'de> for StringOnly<T>
|
||||
where T: ::serde::Deserializer<'de> {
|
||||
type Value = String;
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("string")
|
||||
}
|
||||
fn visit_str<E>(self, value: &str) -> Result<String, E> {
|
||||
Ok(String::from(value))
|
||||
}
|
||||
}
|
||||
let s = d.deserialize_string(StringOnly::<D>(PhantomData))?;
|
||||
$(
|
||||
if stringify!($x).eq_ignore_ascii_case(&s) {
|
||||
return Ok($e::$x);
|
||||
}
|
||||
)*
|
||||
static ALLOWED: &'static[&str] = &[$(stringify!($x),)*];
|
||||
Err(D::Error::unknown_variant(&s, ALLOWED))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::str::FromStr for $e {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
$(
|
||||
if stringify!($x).eq_ignore_ascii_case(s) {
|
||||
return Ok($e::$x);
|
||||
}
|
||||
)*
|
||||
Err("Bad variant")
|
||||
}
|
||||
}
|
||||
|
||||
impl ::config::ConfigType for $e {
|
||||
fn doc_hint() -> String {
|
||||
let mut variants = Vec::new();
|
||||
$(
|
||||
variants.push(stringify!($x));
|
||||
)*
|
||||
format!("[{}]", variants.join("|"))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! msg {
|
||||
($($arg:tt)*) => (
|
||||
match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
|
||||
@ -342,9 +266,9 @@ macro_rules! msg {
|
||||
// For format_missing and last_pos, need to use the source callsite (if applicable).
|
||||
// Required as generated code spans aren't guaranteed to follow on from the last span.
|
||||
macro_rules! source {
|
||||
($this:ident, $sp: expr) => {
|
||||
($this: ident, $sp: expr) => {
|
||||
$sp.source_callsite()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
|
||||
@ -353,28 +277,29 @@ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
|
||||
|
||||
// Return true if the given span does not intersect with file lines.
|
||||
macro_rules! out_of_file_lines_range {
|
||||
($self:ident, $span:expr) => {
|
||||
!$self.config
|
||||
($self: ident, $span: expr) => {
|
||||
!$self
|
||||
.config
|
||||
.file_lines()
|
||||
.intersects(&$self.codemap.lookup_line_range($span))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! skip_out_of_file_lines_range {
|
||||
($self:ident, $span:expr) => {
|
||||
($self: ident, $span: expr) => {
|
||||
if out_of_file_lines_range!($self, $span) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! skip_out_of_file_lines_range_visitor {
|
||||
($self:ident, $span:expr) => {
|
||||
($self: ident, $span: expr) => {
|
||||
if out_of_file_lines_range!($self, $span) {
|
||||
$self.push_rewrite($span, None);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Wraps String in an Option. Returns Some when the string adheres to the
|
@ -12,6 +12,7 @@
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
|
||||
@ -19,8 +20,7 @@ use codemap::SpanUtils;
|
||||
use comment::{combine_strs_with_missing_comments, contains_comment};
|
||||
use expr::rewrite_field;
|
||||
use items::{rewrite_struct_field, rewrite_struct_field_prefix};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListTactic, Separator,
|
||||
SeparatorPlace};
|
||||
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::{Indent, Shape};
|
||||
use spanned::Spanned;
|
||||
@ -247,7 +247,7 @@ fn rewrite_aligned_items_inner<T: AlignedItem>(
|
||||
);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
tactic,
|
||||
separator: ",",
|
||||
trailing_separator: context.config.trailing_comma(),
|
||||
separator_place: SeparatorPlace::Back,
|
@ -10,8 +10,9 @@
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::{ast, visit};
|
||||
use syntax::attr::HasAttrs;
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::codemap::{self, BytePos, CodeMap, Pos, Span};
|
||||
use syntax::parse::ParseSess;
|
||||
|
||||
@ -23,8 +24,7 @@ use config::{BraceStyle, Config};
|
||||
use expr::rewrite_literal;
|
||||
use items::{format_impl, format_trait, format_trait_alias, rewrite_associated_impl_type,
|
||||
rewrite_associated_type, rewrite_type_alias, FnSig, StaticParts, StructParts};
|
||||
use lists::{itemize_list, write_list, DefinitiveListTactic, ListFormatting, SeparatorPlace,
|
||||
SeparatorTactic};
|
||||
use lists::{itemize_list, write_list, ListFormatting};
|
||||
use macros::{rewrite_macro, rewrite_macro_def, MacroPosition};
|
||||
use regex::Regex;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
@ -32,6 +32,34 @@ use shape::{Indent, Shape};
|
||||
use spanned::Spanned;
|
||||
use utils::{self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec};
|
||||
|
||||
/// Returns attributes that are within `outer_span`.
|
||||
pub fn filter_inline_attrs(attrs: &[ast::Attribute], outer_span: Span) -> Vec<ast::Attribute> {
|
||||
attrs
|
||||
.iter()
|
||||
.filter(|a| outer_span.lo() <= a.span.lo() && a.span.hi() <= outer_span.hi())
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns true for `mod foo;`, false for `mod foo { .. }`.
|
||||
fn is_mod_decl(item: &ast::Item) -> bool {
|
||||
match item.node {
|
||||
ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_macro_use_attr(attrs: &[ast::Attribute], span: Span) -> bool {
|
||||
attr::contains_name(&filter_inline_attrs(attrs, span), "macro_use")
|
||||
}
|
||||
|
||||
/// Returns true for `mod foo;` without any inline attributes.
|
||||
/// We cannot reorder modules with attributes because doing so can break the code.
|
||||
/// e.g. `#[macro_use]`.
|
||||
fn is_mod_decl_without_attr(item: &ast::Item) -> bool {
|
||||
is_mod_decl(item) && !contains_macro_use_attr(&item.attrs, item.span())
|
||||
}
|
||||
|
||||
fn is_use_item(item: &ast::Item) -> bool {
|
||||
match item.node {
|
||||
ast::ItemKind::Use(_) => true,
|
||||
@ -39,6 +67,10 @@ fn is_use_item(item: &ast::Item) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_use_item_without_attr(item: &ast::Item) -> bool {
|
||||
is_use_item(item) && !contains_macro_use_attr(&item.attrs, item.span())
|
||||
}
|
||||
|
||||
fn is_extern_crate(item: &ast::Item) -> bool {
|
||||
match item.node {
|
||||
ast::ItemKind::ExternCrate(..) => true,
|
||||
@ -46,6 +78,10 @@ fn is_extern_crate(item: &ast::Item) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_extern_crate_without_attr(item: &ast::Item) -> bool {
|
||||
is_extern_crate(item) && !contains_macro_use_attr(&item.attrs, item.span())
|
||||
}
|
||||
|
||||
/// Creates a string slice corresponding to the specified span.
|
||||
pub struct SnippetProvider<'a> {
|
||||
/// A pointer to the content of the file we are formatting.
|
||||
@ -318,39 +354,26 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
let filtered_attrs;
|
||||
let mut attrs = &item.attrs;
|
||||
match item.node {
|
||||
ast::ItemKind::Mod(ref m) => {
|
||||
let outer_file = self.codemap.lookup_char_pos(item.span.lo()).file;
|
||||
let inner_file = self.codemap.lookup_char_pos(m.inner.lo()).file;
|
||||
if outer_file.name == inner_file.name {
|
||||
// Module is inline, in this case we treat modules like any
|
||||
// other item.
|
||||
if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
|
||||
self.push_skipped_with_span(item.span());
|
||||
return;
|
||||
}
|
||||
} else if contains_skip(&item.attrs) {
|
||||
// Module is not inline, but should be skipped.
|
||||
// Module is inline, in this case we treat it like any other item.
|
||||
_ if !is_mod_decl(item) => {
|
||||
if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
|
||||
self.push_skipped_with_span(item.span());
|
||||
return;
|
||||
} else {
|
||||
// Module is not inline and should not be skipped. We want
|
||||
// to process only the attributes in the current file.
|
||||
filtered_attrs = item.attrs
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
let attr_file = self.codemap.lookup_char_pos(a.span.lo()).file;
|
||||
if attr_file.name == outer_file.name {
|
||||
Some(a.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
// Assert because if we should skip it should be caught by
|
||||
// the above case.
|
||||
assert!(!self.visit_attrs(&filtered_attrs, ast::AttrStyle::Outer));
|
||||
attrs = &filtered_attrs;
|
||||
}
|
||||
}
|
||||
// Module is not inline, but should be skipped.
|
||||
ast::ItemKind::Mod(..) if contains_skip(&item.attrs) => {
|
||||
return;
|
||||
}
|
||||
// Module is not inline and should not be skipped. We want
|
||||
// to process only the attributes in the current file.
|
||||
ast::ItemKind::Mod(..) => {
|
||||
filtered_attrs = filter_inline_attrs(&item.attrs, item.span());
|
||||
// Assert because if we should skip it should be caught by
|
||||
// the above case.
|
||||
assert!(!self.visit_attrs(&filtered_attrs, ast::AttrStyle::Outer));
|
||||
attrs = &filtered_attrs;
|
||||
}
|
||||
_ => {
|
||||
if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
|
||||
self.push_skipped_with_span(item.span());
|
||||
@ -397,8 +420,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
self.last_pos = source!(self, item.span).hi();
|
||||
}
|
||||
ast::ItemKind::Mod(ref module) => {
|
||||
let is_inline = !is_mod_decl(item);
|
||||
self.format_missing_with_indent(source!(self, item.span).lo());
|
||||
self.format_mod(module, &item.vis, item.span, item.ident, attrs);
|
||||
self.format_mod(module, &item.vis, item.span, item.ident, attrs, is_inline);
|
||||
}
|
||||
ast::ItemKind::Mac(ref mac) => {
|
||||
self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
|
||||
@ -439,6 +463,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
ast::ItemKind::MacroDef(ref def) => {
|
||||
let rewrite = rewrite_macro_def(
|
||||
&self.get_context(),
|
||||
self.shape(),
|
||||
self.block_indent,
|
||||
def,
|
||||
item.ident,
|
||||
@ -576,14 +601,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
snippet_provider: &'a SnippetProvider,
|
||||
) -> FmtVisitor<'a> {
|
||||
FmtVisitor {
|
||||
parse_session: parse_session,
|
||||
parse_session,
|
||||
codemap: parse_session.codemap(),
|
||||
buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2),
|
||||
last_pos: BytePos(0),
|
||||
block_indent: Indent::empty(),
|
||||
config: config,
|
||||
config,
|
||||
is_if_else_block: false,
|
||||
snippet_provider: snippet_provider,
|
||||
snippet_provider,
|
||||
line_number: 0,
|
||||
skipped_range: vec![],
|
||||
}
|
||||
@ -649,34 +674,39 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
fn walk_items(&mut self, mut items_left: &[&ast::Item]) {
|
||||
while !items_left.is_empty() {
|
||||
// If the next item is a `use` declaration, then extract it and any subsequent `use`s
|
||||
// to be potentially reordered within `format_imports`. Otherwise, just format the
|
||||
// next item for output.
|
||||
if self.config.reorder_imports() && is_use_item(&*items_left[0]) {
|
||||
let used_items_len = self.reorder_items(
|
||||
items_left,
|
||||
&is_use_item,
|
||||
self.config.reorder_imports_in_group(),
|
||||
);
|
||||
macro try_reorder_items_with($reorder: ident, $in_group: ident, $pred: ident) {
|
||||
if self.config.$reorder() && $pred(&*items_left[0]) {
|
||||
let used_items_len =
|
||||
self.reorder_items(items_left, &$pred, self.config.$in_group());
|
||||
let (_, rest) = items_left.split_at(used_items_len);
|
||||
items_left = rest;
|
||||
} else if self.config.reorder_extern_crates() && is_extern_crate(&*items_left[0]) {
|
||||
let used_items_len = self.reorder_items(
|
||||
items_left,
|
||||
&is_extern_crate,
|
||||
self.config.reorder_extern_crates_in_group(),
|
||||
);
|
||||
let (_, rest) = items_left.split_at(used_items_len);
|
||||
items_left = rest;
|
||||
} else {
|
||||
// `unwrap()` is safe here because we know `items_left`
|
||||
// has elements from the loop condition
|
||||
let (item, rest) = items_left.split_first().unwrap();
|
||||
self.visit_item(item);
|
||||
items_left = rest;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while !items_left.is_empty() {
|
||||
// If the next item is a `use`, `extern crate` or `mod`, then extract it and any
|
||||
// subsequent items that have the same item kind to be reordered within
|
||||
// `format_imports`. Otherwise, just format the next item for output.
|
||||
{
|
||||
try_reorder_items_with!(
|
||||
reorder_imports,
|
||||
reorder_imports_in_group,
|
||||
is_use_item_without_attr
|
||||
);
|
||||
try_reorder_items_with!(
|
||||
reorder_extern_crates,
|
||||
reorder_extern_crates_in_group,
|
||||
is_extern_crate_without_attr
|
||||
);
|
||||
try_reorder_items_with!(reorder_modules, reorder_modules, is_mod_decl_without_attr);
|
||||
}
|
||||
// Reaching here means items were not reordered. There must be at least
|
||||
// one item left in `items_left`, so calling `unwrap()` here is safe.
|
||||
let (item, rest) = items_left.split_first().unwrap();
|
||||
self.visit_item(item);
|
||||
items_left = rest;
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_mod_items(&mut self, m: &ast::Mod) {
|
||||
@ -722,13 +752,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
s: Span,
|
||||
ident: ast::Ident,
|
||||
attrs: &[ast::Attribute],
|
||||
is_internal: bool,
|
||||
) {
|
||||
// Decide whether this is an inline mod or an external mod.
|
||||
let local_file_name = self.codemap.span_to_filename(s);
|
||||
let inner_span = source!(self, m.inner);
|
||||
let is_internal = !(inner_span.lo().0 == 0 && inner_span.hi().0 == 0)
|
||||
&& local_file_name == self.codemap.span_to_filename(inner_span);
|
||||
|
||||
self.push_str(&*utils::format_visibility(vis));
|
||||
self.push_str("mod ");
|
||||
self.push_str(&ident.to_string());
|
@ -8,14 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate regex;
|
||||
extern crate rustfmt_nightly as rustfmt;
|
||||
extern crate rustfmt_config as config;
|
||||
extern crate rustfmt_core as rustfmt;
|
||||
extern crate term;
|
||||
|
||||
use std::collections::HashMap;
|
||||
@ -26,8 +25,9 @@ use std::path::{Path, PathBuf};
|
||||
use std::str::Chars;
|
||||
|
||||
use rustfmt::*;
|
||||
use rustfmt::config::{Color, Config, ReportTactic};
|
||||
use rustfmt::filemap::{write_system_newlines, FileMap};
|
||||
use config::{Color, Config, ReportTactic};
|
||||
use config::summary::Summary;
|
||||
use rustfmt::filemap::write_system_newlines;
|
||||
use rustfmt::rustfmt_diff::*;
|
||||
|
||||
const DIFF_CONTEXT_SIZE: usize = 3;
|
||||
@ -95,7 +95,7 @@ fn verify_config_test_names() {
|
||||
let config_name = path.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
// Make sure that config name is used in the files in the directory.
|
||||
verify_config_used(&path, &config_name);
|
||||
verify_config_used(&path, config_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ fn verify_config_test_names() {
|
||||
// println!) that is used by `rustfmt::rustfmt_diff::print_diff`. Writing
|
||||
// using only one or the other will cause the output order to differ when
|
||||
// `print_diff` selects the approach not used.
|
||||
fn write_message(msg: String) {
|
||||
fn write_message(msg: &str) {
|
||||
let mut writer = OutputWriter::new(Color::Auto);
|
||||
writer.writeln(&format!("{}", msg), None);
|
||||
}
|
||||
@ -210,10 +210,26 @@ fn idempotence_tests() {
|
||||
// no warnings are emitted.
|
||||
#[test]
|
||||
fn self_tests() {
|
||||
let mut files = get_test_files(Path::new("src/bin"), false);
|
||||
files.append(&mut get_test_files(Path::new("tests"), false));
|
||||
files.push(PathBuf::from("src/lib.rs"));
|
||||
files.push(PathBuf::from("build.rs"));
|
||||
let mut files = get_test_files(Path::new("tests"), false);
|
||||
let bin_directories = vec![
|
||||
"cargo-fmt",
|
||||
"git-rustfmt",
|
||||
"rustfmt-bin",
|
||||
"rustfmt-format-diff",
|
||||
];
|
||||
for dir in bin_directories {
|
||||
let mut path = PathBuf::from("..");
|
||||
path.push(dir);
|
||||
path.push("src/main.rs");
|
||||
files.push(path);
|
||||
}
|
||||
let lib_directories = vec!["rustfmt-core", "rustfmt-config"];
|
||||
for dir in lib_directories {
|
||||
let mut path = PathBuf::from("..");
|
||||
path.push(dir);
|
||||
path.push("src/lib.rs");
|
||||
files.push(path);
|
||||
}
|
||||
|
||||
let (reports, count, fails) = check_files(files);
|
||||
let mut warnings = 0;
|
||||
@ -285,6 +301,16 @@ fn format_lines_errors_are_reported() {
|
||||
assert!(error_summary.has_formatting_errors());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_lines_errors_are_reported_with_tabs() {
|
||||
let long_identifier = String::from_utf8(vec![b'a'; 97]).unwrap();
|
||||
let input = Input::Text(format!("fn a() {{\n\t{}\n}}", long_identifier));
|
||||
let config = Config::from_toml("hard_tabs = true").unwrap();
|
||||
let (error_summary, _file_map, _report) =
|
||||
format_input::<io::Stdout>(input, &config, None).unwrap();
|
||||
assert!(error_summary.has_formatting_errors());
|
||||
}
|
||||
|
||||
// For each file, run rustfmt and collect the output.
|
||||
// Returns the number of files checked and the number of failures.
|
||||
fn check_files(files: Vec<PathBuf>) -> (Vec<FormatReport>, u32, u32) {
|
||||
@ -373,8 +399,8 @@ pub enum IdempotentCheckError {
|
||||
}
|
||||
|
||||
pub fn idempotent_check(filename: &PathBuf) -> Result<FormatReport, IdempotentCheckError> {
|
||||
let sig_comments = read_significant_comments(&filename);
|
||||
let config = read_config(&filename);
|
||||
let sig_comments = read_significant_comments(filename);
|
||||
let config = read_config(filename);
|
||||
let (error_summary, file_map, format_report) = format_file(filename, &config);
|
||||
if error_summary.has_parsing_errors() {
|
||||
return Err(IdempotentCheckError::Parse);
|
||||
@ -663,10 +689,12 @@ impl ConfigCodeBlock {
|
||||
|
||||
fn get_block_config(&self) -> Config {
|
||||
let mut config = Config::default();
|
||||
config.override_value(
|
||||
self.config_name.as_ref().unwrap(),
|
||||
self.config_value.as_ref().unwrap(),
|
||||
);
|
||||
if self.config_value.is_some() && self.config_value.is_some() {
|
||||
config.override_value(
|
||||
self.config_name.as_ref().unwrap(),
|
||||
self.config_value.as_ref().unwrap(),
|
||||
);
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
@ -674,16 +702,24 @@ impl ConfigCodeBlock {
|
||||
// We never expect to not have a code block.
|
||||
assert!(self.code_block.is_some() && self.code_block_start.is_some());
|
||||
|
||||
if self.config_name.is_none() {
|
||||
write_message(format!(
|
||||
// See if code block begins with #![rustfmt_skip].
|
||||
let fmt_skip = self.code_block
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.split("\n")
|
||||
.nth(0)
|
||||
.unwrap_or("") == "#![rustfmt_skip]";
|
||||
|
||||
if self.config_name.is_none() && !fmt_skip {
|
||||
write_message(&format!(
|
||||
"No configuration name for {}:{}",
|
||||
CONFIGURATIONS_FILE_NAME,
|
||||
self.code_block_start.unwrap()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
if self.config_value.is_none() {
|
||||
write_message(format!(
|
||||
if self.config_value.is_none() && !fmt_skip {
|
||||
write_message(&format!(
|
||||
"No configuration value for {}:{}",
|
||||
CONFIGURATIONS_FILE_NAME,
|
||||
self.code_block_start.unwrap()
|
||||
@ -695,7 +731,7 @@ impl ConfigCodeBlock {
|
||||
|
||||
fn has_parsing_errors(&self, error_summary: Summary) -> bool {
|
||||
if error_summary.has_parsing_errors() {
|
||||
write_message(format!(
|
||||
write_message(&format!(
|
||||
"\u{261d}\u{1f3fd} Cannot format {}:{}",
|
||||
CONFIGURATIONS_FILE_NAME,
|
||||
self.code_block_start.unwrap()
|
||||
@ -718,7 +754,7 @@ impl ConfigCodeBlock {
|
||||
});
|
||||
}
|
||||
|
||||
fn formatted_has_diff(&self, file_map: FileMap) -> bool {
|
||||
fn formatted_has_diff(&self, file_map: &FileMap) -> bool {
|
||||
let &(ref _file_name, ref text) = file_map.first().unwrap();
|
||||
let compare = make_diff(self.code_block.as_ref().unwrap(), text, DIFF_CONTEXT_SIZE);
|
||||
if !compare.is_empty() {
|
||||
@ -744,14 +780,14 @@ impl ConfigCodeBlock {
|
||||
let (error_summary, file_map, _report) =
|
||||
format_input::<io::Stdout>(input, &config, None).unwrap();
|
||||
|
||||
!self.has_parsing_errors(error_summary) && !self.formatted_has_diff(file_map)
|
||||
!self.has_parsing_errors(error_summary) && !self.formatted_has_diff(&file_map)
|
||||
}
|
||||
|
||||
// Extract a code block from the iterator. Behavior:
|
||||
// - Rust code blocks are identifed by lines beginning with "```rust".
|
||||
// - One explicit configuration setting is supported per code block.
|
||||
// - Rust code blocks with no configuration setting are illegal and cause an
|
||||
// assertion failure.
|
||||
// assertion failure, unless the snippet begins with #![rustfmt_skip].
|
||||
// - Configuration names in Configurations.md must be in the form of
|
||||
// "## `NAME`".
|
||||
// - Configuration values in Configurations.md must be in the form of
|
||||
@ -761,7 +797,7 @@ impl ConfigCodeBlock {
|
||||
prev: Option<&ConfigCodeBlock>,
|
||||
) -> Option<ConfigCodeBlock> {
|
||||
let mut code_block = ConfigCodeBlock::new();
|
||||
code_block.config_name = prev.map_or(None, |cb| cb.config_name.clone());
|
||||
code_block.config_name = prev.and_then(|cb| cb.config_name.clone());
|
||||
|
||||
loop {
|
||||
match ConfigurationSection::get_section(file) {
|
||||
@ -790,7 +826,7 @@ fn configuration_snippet_tests() {
|
||||
// entry for each Rust code block found.
|
||||
fn get_code_blocks() -> Vec<ConfigCodeBlock> {
|
||||
let mut file_iter = BufReader::new(
|
||||
fs::File::open(CONFIGURATIONS_FILE_NAME)
|
||||
fs::File::open(Path::new("..").join(CONFIGURATIONS_FILE_NAME))
|
||||
.expect(&format!("Couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
|
||||
).lines()
|
||||
.map(|l| l.unwrap())
|
@ -214,3 +214,18 @@ impl Foo {
|
||||
}).collect();
|
||||
}
|
||||
}
|
||||
|
||||
// #2415
|
||||
// Avoid orphan in chain
|
||||
fn issue2415() {
|
||||
let base_url = (|| {
|
||||
// stuff
|
||||
|
||||
Ok((|| {
|
||||
// stuff
|
||||
Some(value.to_string())
|
||||
})()
|
||||
.ok_or("")?)
|
||||
})()
|
||||
.unwrap_or_else(|_: Box<::std::error::Error>| String::from(""));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user