+ emit_mode: EmitMode, EmitMode::Files, false,
+ "What emit Mode to use when none is supplied";
+ make_backup: bool, false, false, "Backup changed files";
+ print_misformatted_file_names: bool, false, true,
+ "Prints the names of mismatched files that were formatted. Prints the names of \
+ files that would be formated when used with `--check` mode. ";
+}
+
+#[derive(Error, Debug)]
+#[error("Could not output config: {0}")]
+pub struct ToTomlError(toml::ser::Error);
+
+impl PartialConfig {
+ pub fn to_toml(&self) -> Result<String, ToTomlError> {
+ // 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;
+ cloned.print_misformatted_file_names = None;
+ cloned.merge_imports = None;
+
+ ::toml::to_string(&cloned).map_err(ToTomlError)
+ }
+}
+
+impl Config {
+ pub(crate) fn version_meets_requirement(&self) -> 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,
+ );
+ return false;
+ }
+ }
+
+ true
+ }
+
+ /// Constructs 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`.
+ ///
+ /// Returns a `Config` if the config could be read and parsed from
+ /// the file, otherwise errors.
+ pub(super) 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, file_path.parent().unwrap())
+ .map_err(|err| Error::new(ErrorKind::InvalidData, err))
+ }
+
+ /// Resolves 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(super) 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() {
+ break;
+ }
+ }
+
+ // If nothing was found, check in the home directory.
+ if let Some(home_dir) = dirs::home_dir() {
+ if let Some(path) = get_toml_path(&home_dir)? {
+ return Ok(Some(path));
+ }
+ }
+
+ // If none was found ther either, check in the user's configuration directory.
+ if let Some(mut config_dir) = dirs::config_dir() {
+ config_dir.push("rustfmt");
+ if let Some(path) = get_toml_path(&config_dir)? {
+ return Ok(Some(path));
+ }
+ }
+
+ 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(crate) 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::new();
+ let table = parsed
+ .as_table()
+ .ok_or_else(|| String::from("Parsed config was not table"))?;
+ for key in table.keys() {
+ if !Config::is_valid_name(key) {
+ 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, dir))
+ }
+ 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)
+ }
+ }
+ }