Merge pull request #2419 from topecongiro/core
Separate rustfmt into multiple crates
This commit is contained in:
commit
8f8ee9e660
99
Cargo.lock
generated
99
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"
|
||||
@ -109,6 +118,17 @@ name = "getopts"
|
||||
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.42"
|
||||
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]]
|
||||
@ -293,14 +332,32 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "0.3.8"
|
||||
name = "rustfmt-bin"
|
||||
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.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 = [
|
||||
"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)",
|
||||
"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)",
|
||||
@ -308,13 +365,23 @@ dependencies = [
|
||||
"regex 0.2.5 (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.42 (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)",
|
||||
]
|
||||
|
||||
@ -505,12 +572,14 @@ 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.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9936036cc70fe4a8b2d338ab665900323290efb03983c86cbe235ae800ad8017"
|
||||
"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 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
|
||||
|
67
Cargo.toml
67
Cargo.toml
@ -1,58 +1,9 @@
|
||||
[package]
|
||||
|
||||
name = "rustfmt-nightly"
|
||||
version = "0.3.8"
|
||||
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 = "29.0.0"
|
||||
rustc-ap-rustc_errors = "29.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",
|
||||
]
|
||||
|
@ -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"
|
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>;
|
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.get().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)]
|
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.
|
||||
|
244
rustfmt-config/src/options.rs
Normal file
244
rustfmt-config/src/options.rs
Normal file
@ -0,0 +1,244 @@
|
||||
// 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,
|
||||
}
|
||||
|
||||
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};
|
@ -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;
|
@ -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};
|
@ -19,10 +19,7 @@ use config::{Config, NewlineStyle, WriteMode};
|
||||
use rustfmt_diff::{make_diff, 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;
|
@ -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)]
|
||||
@ -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;
|
@ -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;
|
@ -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,14 +41,13 @@ 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;
|
||||
@ -60,9 +56,7 @@ mod checkstyle;
|
||||
mod closures;
|
||||
pub mod codemap;
|
||||
mod comment;
|
||||
pub mod config;
|
||||
mod expr;
|
||||
pub mod file_lines;
|
||||
pub mod filemap;
|
||||
mod imports;
|
||||
mod issues;
|
||||
@ -77,11 +71,15 @@ pub mod rustfmt_diff;
|
||||
mod shape;
|
||||
mod spanned;
|
||||
mod string;
|
||||
mod summary;
|
||||
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 {
|
||||
// Line has exceeded character limit (found, maximum)
|
@ -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,
|
@ -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,8 +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, DefinitiveListTactic, ListFormatting, SeparatorPlace,
|
||||
SeparatorTactic};
|
||||
use lists::{itemize_list, write_list, ListFormatting};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use shape::{Indent, Shape};
|
||||
use utils::{format_visibility, mk_sp};
|
@ -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;
|
@ -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;
|
@ -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)* ) {
|
@ -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;
|
@ -10,6 +10,7 @@
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use config::lists::*;
|
||||
use syntax::{ast, visit};
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::codemap::{self, BytePos, CodeMap, Pos, Span};
|
||||
@ -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};
|
@ -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,10 @@ 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 config::file_lines::FileLines;
|
||||
use rustfmt::filemap::write_system_newlines;
|
||||
use rustfmt::rustfmt_diff::*;
|
||||
|
||||
const DIFF_CONTEXT_SIZE: usize = 3;
|
||||
@ -186,10 +187,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;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user