Merge pull request #2522 from topecongiro/ignore-config-option

Add ignore config option
This commit is contained in:
Nick Cameron 2018-03-12 16:25:31 +13:00 committed by GitHub
commit a0e063a6e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 104 additions and 11 deletions

View File

@ -2135,3 +2135,30 @@ Copyright 2018 The Rust Project Developers.`, etc.:
```
`\{`, `\}` and `\\` match literal braces / backslashes.
## `ignore`
Skip formatting the specified files and directories.
- **Default value**: format every files
- **Possible values**: See an example below
- **Stable**: No
### Example
If you want to ignore specific files, put the following to your config file:
```toml
ignore = [
"src/types.rs",
"src/foo/bar.rs",
]
```
If you want to ignore every file under `examples/`, put the following to your config file:
```toml
ignore [
"examples",
]
```

View File

@ -18,6 +18,7 @@
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use getopts::{Matches, Options};
@ -25,8 +26,6 @@
use rustfmt::config::file_lines::FileLines;
use rustfmt::{run, FileName, Input, Summary};
use std::str::FromStr;
type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

View File

@ -9,7 +9,7 @@
// except according to those terms.
use config::file_lines::FileLines;
use config::options::WidthHeuristics;
use config::options::{IgnoreList, WidthHeuristics};
/// Trait for types that can be used in `Config`.
pub trait ConfigType: Sized {
@ -54,6 +54,12 @@ fn doc_hint() -> String {
}
}
impl ConfigType for IgnoreList {
fn doc_hint() -> String {
String::from("[<string>,..]")
}
}
/// Check if we're in a nightly build.
///
/// The environment variable `CFG_RELEASE_CHANNEL` is set during the rustc bootstrap
@ -176,7 +182,7 @@ pub fn was_set<'a>(&'a self) -> ConfigWasSet<'a> {
ConfigWasSet(self)
}
fn fill_from_parsed_config(mut self, parsed: PartialConfig) -> Config {
fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
$(
if let Some(val) = parsed.$i {
if self.$i.3 {
@ -195,6 +201,7 @@ fn fill_from_parsed_config(mut self, parsed: PartialConfig) -> Config {
)+
self.set_heuristics();
self.set_license_template();
self.set_ignore(dir);
self
}
@ -216,7 +223,7 @@ pub fn is_valid_name(name: &str) -> bool {
}
}
pub fn from_toml(toml: &str) -> Result<Config, String> {
pub fn from_toml(toml: &str, dir: &Path) -> Result<Config, String> {
let parsed: ::toml::Value =
toml.parse().map_err(|e| format!("Could not parse TOML: {}", e))?;
let mut err: String = String::new();
@ -236,7 +243,7 @@ pub fn from_toml(toml: &str) -> Result<Config, String> {
if !err.is_empty() {
eprint!("{}", err);
}
Ok(Config::default().fill_from_parsed_config(parsed_config))
Ok(Config::default().fill_from_parsed_config(parsed_config, dir: &Path))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
@ -300,7 +307,8 @@ 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))
Config::from_toml(&toml, file_path.parent().unwrap())
.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
/// Resolve the config for input in `dir`.
@ -401,6 +409,10 @@ fn set_license_template(&mut self) {
}
}
}
fn set_ignore(&mut self, dir: &Path) {
self.ignore.2.add_prefix(dir);
}
}
// Template for the default configuration

View File

@ -141,6 +141,8 @@
"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";
ignore: IgnoreList, IgnoreList::default(), false,
"Skip formatting the specified files and directories.";
// Not user-facing.
verbose: bool, false, false, "Use verbose output";
@ -208,7 +210,8 @@ fn test_config_used_to_toml() {
#[test]
fn test_was_set() {
let config = Config::from_toml("hard_tabs = true").unwrap();
use std::path::Path;
let config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();
assert_eq!(config.was_set().hard_tabs(), true);
assert_eq!(config.was_set().verbose(), false);

View File

@ -8,9 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::codemap::FileName;
use config::config_type::ConfigType;
use config::lists::*;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
/// Macro for deriving implementations of Serialize/Deserialize for enums
#[macro_export]
macro_rules! impl_enum_serialize_and_deserialize {
@ -244,3 +249,50 @@ fn from_str(_: &str) -> Result<Self, Self::Err> {
Err("WidthHeuristics is not parsable")
}
}
/// A set of directories, files and modules that rustfmt should ignore.
#[derive(Default, Deserialize, Serialize, Clone, Debug)]
pub struct IgnoreList(HashSet<PathBuf>);
impl IgnoreList {
pub fn add_prefix(&mut self, dir: &Path) {
self.0 = self.0
.iter()
.map(|s| {
if s.has_root() {
s.clone()
} else {
let mut path = PathBuf::from(dir);
path.push(s);
path
}
})
.collect();
}
fn skip_file_inner(&self, file: &Path) -> bool {
for path in &self.0 {
if file.starts_with(path) {
return true;
}
}
false
}
pub fn skip_file(&self, file: &FileName) -> bool {
if let FileName::Real(ref path) = file {
self.skip_file_inner(path)
} else {
false
}
}
}
impl ::std::str::FromStr for IgnoreList {
type Err = &'static str;
fn from_str(_: &str) -> Result<Self, Self::Err> {
Err("IgnoreList is not parsable")
}
}

View File

@ -341,7 +341,7 @@ fn format_ast<F>(
// nothing to distinguish the nested module contents.
let skip_children = config.skip_children() || config.write_mode() == config::WriteMode::Plain;
for (path, module) in modules::list_files(krate, parse_session.codemap())? {
if skip_children && path != *main_file {
if (skip_children && path != *main_file) || config.ignore().skip_file(&path) {
continue;
}
should_emit_verbose(&path, config, || println!("Formatting {}", path));

View File

@ -293,7 +293,7 @@ fn format_lines_errors_are_reported() {
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 config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();
let (error_summary, _file_map, _report) =
format_input::<io::Stdout>(input, &config, None).unwrap();
assert!(error_summary.has_formatting_errors());
@ -435,7 +435,7 @@ fn get_config(config_file: Option<&Path>) -> Config {
.read_to_string(&mut def_config)
.expect("Couldn't read config");
Config::from_toml(&def_config).expect("Invalid toml")
Config::from_toml(&def_config, Path::new("tests/config/")).expect("Invalid toml")
}
// Reads significant comments of the form: // rustfmt-key: value