From 26281726dbd6a694c9a415b5b84331b68d6fee10 Mon Sep 17 00:00:00 2001 From: xxchan Date: Fri, 25 Feb 2022 22:35:59 +0200 Subject: [PATCH 01/24] formatting logic of Cargo.toml --- Cargo.lock | 38 ++++ Cargo.toml | 1 + src/formatting.rs | 1 + src/formatting/cargo_toml.rs | 398 +++++++++++++++++++++++++++++++++++ 4 files changed, 438 insertions(+) create mode 100644 src/formatting/cargo_toml.rs diff --git a/Cargo.lock b/Cargo.lock index e5175528970..5def1acd345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,12 @@ dependencies = [ "packed_simd_2", ] +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "camino" version = "1.0.7" @@ -135,6 +141,16 @@ dependencies = [ "syn", ] +[[package]] +name = "combine" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -331,6 +347,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "kstring" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526" +dependencies = [ + "serde", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -509,6 +534,7 @@ dependencies = [ "term", "thiserror", "toml", + "toml_edit", "unicode-segmentation", "unicode-width", "unicode_categories", @@ -656,6 +682,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b" +dependencies = [ + "combine", + "indexmap", + "itertools", + "kstring", +] + [[package]] name = "unicode-segmentation" version = "1.9.0" diff --git a/Cargo.toml b/Cargo.toml index 7438335eaa7..f78a9453813 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ serde_json = "1.0" term = "0.7" thiserror = "1.0" toml = "0.5" +toml_edit = "0.13" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" diff --git a/src/formatting.rs b/src/formatting.rs index 1dfd8a514f0..2a3da24d15d 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -18,6 +18,7 @@ use crate::utils::{contains_skip, count_newlines}; use crate::visitor::FmtVisitor; use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session}; +mod cargo_toml; mod generated; mod newline_style; diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs new file mode 100644 index 00000000000..d351a3f8954 --- /dev/null +++ b/src/formatting/cargo_toml.rs @@ -0,0 +1,398 @@ +use itertools::Itertools; +use std::cmp::Ordering; +use toml_edit::{visit_mut::*, Decor, Document, Formatted, Item, KeyMut, Table, TableLike, Value}; + +use crate::Config; + +#[allow(dead_code)] +fn format_cargo_toml(content: &str, config: &Config) -> String { + let mut doc = content.parse::().unwrap(); + let rules: Vec> = vec![ + Box::new(SortSection { + current_position: 0, + }), + Box::new(SortKey), + Box::new(BlankLine { trimming: true }), + Box::new(KeyValue), + Box::new(MultiLine), + Box::new(WrapArray { + max_width: config.max_width(), + }), + Box::new(FormatInlineTable { + max_width: config.max_width(), + long_tables: vec![], + current_section: String::new(), + }), + ]; + for mut rule in rules.into_iter() { + rule.visit_document_mut(&mut doc); + } + return doc.to_string(); +} + +/// Sort key names alphabetically within each section, with the exception of the +/// `[package]` section. +/// +/// In `[package]` section, +/// put the `name` and `version` keys in that order at the top of that section, +/// followed by the remaining keys other than `description` in alphabetical order, +/// followed by the `description` at the end of that section. +struct SortKey; + +/// Put the `[package]` section at the top of the file +struct SortSection { + /// `cargo-edit` uses a `position` field to put tables back in their original order when + /// serialising. We should reset this field after sorting. + current_position: usize, +} + +/// Put a blank line between the last key-value pair in a section and the header of the next +/// section. +/// +/// Do not place a blank line between section headers and the key-value pairs in that section, or +/// between key-value pairs in a section. +/// +/// Should be applied after `SortSection`. +struct BlankLine { + trimming: bool, +} + +/// Don't use quotes around any standard key names; use bare keys. Only use quoted +/// keys for non-standard keys whose names require them, and avoid introducing such +/// key names when possible. +/// +/// Put a single space both before and after the = between a key and value. +/// Do not indent any key names; start all key names at the start of a line. +struct KeyValue; + +/// Use multi-line strings (rather than newline escape sequences) for any string values +/// that include multiple lines, such as the crate description. +struct MultiLine; + +/// For array values, such as a list of authors, put the entire list on the same line as the key, +/// if it fits. Otherwise, use block indentation: put a newline after the opening square bracket, +/// indent each item by one indentation level, put a comma after each item (including the last), +/// and put the closing square bracket at the start of a line by itself after the last item. +/// +/// ```toml +/// authors = [ +/// "A Uthor ", +/// "Another Author ", +/// ] +///``` +struct WrapArray { + max_width: usize, +} + +/// For table values, such as a crate dependency with a path, write the entire +/// table using curly braces and commas on the same line as the key if it fits. If +/// the entire table does not fit on the same line as the key, separate it out into +/// a separate section with key-value pairs: +/// +/// ```toml +/// [dependencies] +/// crate1 = { path = "crate1", version = "1.2.3" } +/// +/// [dependencies.extremely_long_crate_name_goes_here] +/// path = "extremely_long_path_name_goes_right_here" +/// version = "4.5.6" +/// ``` +struct FormatInlineTable { + max_width: usize, + /// Must be `InlineTable` + long_tables: Vec<(String, String, Item)>, + current_section: String, +} + +impl VisitMut for SortKey { + fn visit_document_mut(&mut self, doc: &mut Document) { + doc.as_table_mut().iter_mut().for_each(|(key, section)| { + if key == "package" { + let table = section.as_table_mut().expect("package should be a table"); + // "name" is the first, "version" is the second, "description" is the last + // everything else is sorted alphabetically + table.sort_values_by(|k1, _, k2, _| match (k1.get(), k2.get()) { + ("name", _) => Ordering::Less, + (_, "name") => Ordering::Greater, + ("version", _) => Ordering::Less, + (_, "version") => Ordering::Greater, + ("description", _) => Ordering::Greater, + (_, "description") => Ordering::Less, + _ => k1.cmp(k2), + }) + } else { + self.visit_item_mut(section) + } + }); + } + + fn visit_table_like_mut(&mut self, table: &mut dyn TableLike) { + table.sort_values(); + } +} + +impl BlankLine { + /// trim blank lines at the beginning and end + fn trim_blank_lines(s: &str) -> String { + if !s.contains('\n') { + return s.to_string(); + } + + let num_lines = s.lines().count(); + + if let Some((first_line, _)) = s.lines().find_position(|line| !line.trim().is_empty()) { + // last_line may be equal to first_line + let (mut last_line, _) = s + .lines() + .rev() + .find_position(|line| !line.trim().is_empty()) + .unwrap(); + last_line = num_lines - last_line; + s.lines() + .skip(first_line) + .take(last_line - first_line) + .join("\n") + + "\n" + } else { + String::new() + } + } + + fn trim_decor_blank_lines(decor: &mut Decor) { + let prefix = decor.prefix().unwrap_or("").to_owned(); + let suffix = decor.suffix().unwrap_or("").to_owned(); + decor.set_prefix(Self::trim_blank_lines(prefix.as_str())); + decor.set_suffix(Self::trim_blank_lines(suffix.as_str())); + } +} + +impl VisitMut for BlankLine { + fn visit_document_mut(&mut self, doc: &mut Document) { + doc.as_table_mut() + .iter_mut() + .for_each(|(mut key, section)| { + Self::trim_decor_blank_lines(key.decor_mut()); + self.visit_item_mut(section); + }); + + self.trimming = false; + doc.as_table_mut() + .iter_mut() + .skip(1) + .for_each(|(_, section)| self.visit_item_mut(section)) + } + + fn visit_table_mut(&mut self, table: &mut Table) { + if self.trimming { + Self::trim_decor_blank_lines(table.decor_mut()); + table.iter_mut().for_each(|(mut key, _)| { + Self::trim_decor_blank_lines(key.decor_mut()); + }); + } else { + let decor = table.decor_mut(); + let prefix = decor.prefix().unwrap_or("").to_owned(); + decor.set_prefix("\n".to_owned() + &prefix); + } + } +} + +impl KeyValue { + /// Bare keys can contain ASCII letters, ASCII digits, underscores, and dashes `(A-Za-z0-9_-)`. + fn can_be_bare_key(key: &str) -> bool { + key.chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-') + } +} + +impl VisitMut for KeyValue { + fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { + let prefix = key.decor().prefix().unwrap_or("").to_owned(); + if Self::can_be_bare_key(key.get()) { + // will remove decors and set the key to the bare key + key.fmt(); + } else { + // add a space after the key + key.decor_mut().set_suffix(" "); + } + // start all key names at the start of a line, but preserve comments + key.decor_mut() + .set_prefix(prefix.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')); + + if let Some(v) = value.as_value_mut() { + v.decor_mut().set_prefix(" "); + } + + self.visit_item_mut(value); + } +} + +impl VisitMut for SortSection { + fn visit_document_mut(&mut self, doc: &mut Document) { + // put package at the beginning, others unchanged + doc.as_table_mut().sort_values_by(|k1, _, k2, _| { + if k1.get() == "package" { + Ordering::Less + } else if k2.get() == "package" { + Ordering::Greater + } else { + Ordering::Equal + } + }); + + doc.as_table_mut().iter_mut().for_each(|(_, section)| { + self.visit_item_mut(section); + }); + } + + fn visit_table_mut(&mut self, table: &mut Table) { + table.set_position(self.current_position); + self.current_position += 1; + } +} + +impl VisitMut for MultiLine { + fn visit_string_mut(&mut self, s: &mut Formatted) { + s.fmt(); + } +} + +impl VisitMut for WrapArray { + fn visit_table_like_kv_mut(&mut self, key: KeyMut<'_>, node: &mut Item) { + if let Some(array) = node.as_array_mut() { + // Format to [item1, item2, ...] + array.fmt(); + // Length of key doesn't include decor. Length of array does. So we add 2 (" ="). + if key.get().len() + 2 + array.to_string().len() > self.max_width { + array.iter_mut().for_each(|item| { + item.decor_mut().set_prefix("\n "); + }); + array + .iter_mut() + .last() + .unwrap() + .decor_mut() + .set_suffix("\n"); + } + } + self.visit_item_mut(node); + } +} + +impl VisitMut for FormatInlineTable { + fn visit_document_mut(&mut self, doc: &mut Document) { + doc.as_table_mut().iter_mut().for_each(|(key, section)| { + self.current_section = key.to_owned(); + self.visit_table_like_kv_mut(key, section); + }); + + let mut long_tables = vec![]; + std::mem::swap(&mut self.long_tables, &mut long_tables); + + println!("\n\n long tables\n {:?}\n\n", long_tables); + long_tables.into_iter().for_each(|(section, key, table)| { + match table { + Item::Value(Value::InlineTable(table)) => { + // let table = format!("[{}]\n{}",key,table).parse::().unwrap(); + doc[§ion][&key] = Item::Table(table.into_table()); + } + _ => unreachable!(), + } + }); + } + + fn visit_table_like_mut(&mut self, table: &mut dyn TableLike) { + let mut long_table_keys = vec![]; + + table.iter_mut().for_each(|(key, node)| { + if let Some(table) = node.as_inline_table_mut() { + // Format to { k1 = v1, k2 = v2, ...} + table.fmt(); + // Length of key doesn't include decor. Length of array does. So we add 2 (" ="). + if key.get().len() + 2 + table.to_string().len() > self.max_width { + long_table_keys.push(key.get().to_owned()); + } + } + }); + + long_table_keys.into_iter().for_each(|key| { + let item = table.remove(&key).unwrap(); + println!("removed long item {:?}", item); + self.long_tables + .push((self.current_section.clone(), key, item)); + }); + + table.iter_mut().for_each(|(_, node)| { + self.visit_item_mut(node); + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cargo_toml() { + #[rustfmt::skip] + let s = r#" + + +[[bin]] + "aa" = 1 + 'bb' = 2 + "啊"=1 +[package] + version = 1 + description = "a\nb\nhaha" + name = 3 + arr1 = [1, + 2,3] + + + arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] + +[dependencies] + extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} + crate1 = { path = "crate1",version = "1.2.3" } + +[[bin]] + d = "git-rustfmt" + c = "src/git-rustfmt/main.rs""#; + + let formatted = format_cargo_toml(s, &Default::default()); + + #[rustfmt::skip] + let expected = r#"[package] +name = 3 +version = 1 +arr1 = [1, 2, 3] +arr2 = [ + "11111111111111111111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111111111111111111" +] +description = """ +a +b +haha""" + +[[bin]] +aa = 1 +bb = 2 +"啊" = 1 + +[[bin]] +c = "src/git-rustfmt/main.rs" +d = "git-rustfmt" + +[dependencies] +crate1 = { path = "crate1", version = "1.2.3" } + +[dependencies.extremely_long_crate_name_goes_here] +path = "extremely_long_path_name_goes_right_here" +version = "4.5.6" +"#; + + println!("{}", formatted); + assert_eq!(formatted, expected); + } +} From 933ce853c44f5d8f7314037ae5c36b9a41ce3155 Mon Sep 17 00:00:00 2001 From: xxchan Date: Fri, 25 Feb 2022 22:47:57 +0200 Subject: [PATCH 02/24] test comments --- src/formatting/cargo_toml.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index d351a3f8954..d3ec970d402 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -345,9 +345,13 @@ mod tests { version = 1 description = "a\nb\nhaha" name = 3 + +# comment 1 + arr1 = [1, 2,3] +# comment 2 arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] @@ -365,7 +369,9 @@ mod tests { let expected = r#"[package] name = 3 version = 1 +# comment 1 arr1 = [1, 2, 3] +# comment 2 arr2 = [ "11111111111111111111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111111111111111111111111" From 22bcae2048ed783111e3fd19c09d838eba0274c6 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Mon, 18 Apr 2022 23:25:50 -0400 Subject: [PATCH 03/24] impl From for ErrorKind Improves the ergonomics of calling `IgnorePathSet::from_ignore_list` --- src/ignore_path.rs | 7 +++++++ src/parse/session.rs | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ignore_path.rs b/src/ignore_path.rs index d955949496a..609505258bd 100644 --- a/src/ignore_path.rs +++ b/src/ignore_path.rs @@ -1,6 +1,7 @@ use ignore::{self, gitignore}; use crate::config::{FileName, IgnoreList}; +use crate::ErrorKind; pub(crate) struct IgnorePathSet { ignore_set: gitignore::Gitignore, @@ -30,6 +31,12 @@ impl IgnorePathSet { } } +impl From for ErrorKind { + fn from(error: ignore::Error) -> Self { + ErrorKind::InvalidGlobPattern(error) + } +} + #[cfg(test)] mod test { use rustfmt_config_proc_macro::nightly_only_test; diff --git a/src/parse/session.rs b/src/parse/session.rs index 23db5421910..305c5392c6a 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -142,10 +142,7 @@ fn default_handler( impl ParseSess { pub(crate) fn new(config: &Config) -> Result { - let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) { - Ok(ignore_path_set) => Lrc::new(ignore_path_set), - Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)), - }; + let ignore_path_set = Lrc::new(IgnorePathSet::from_ignore_list(&config.ignore())?); let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); let can_reset_errors = Lrc::new(AtomicBool::new(false)); From a64778eca7dc4bd5b81a9301db2e4c6b5afcf83e Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Mon, 18 Apr 2022 23:30:22 -0400 Subject: [PATCH 04/24] Add `format_cargo_toml` to the code path called by rustfmt Now users can provide the path to their `Cargo.toml` files for rustfmt to format. --- src/formatting.rs | 43 ++++++++++++++++++++++++++++++++---- src/formatting/cargo_toml.rs | 22 ++++++++++++------ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index 2a3da24d15d..892c8d5132c 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -1,7 +1,9 @@ // High level formatting functions. use std::collections::HashMap; +use std::ffi::OsStr; use std::io::{self, Write}; +use std::path::PathBuf; use std::time::{Duration, Instant}; use rustc_ast::ast; @@ -11,6 +13,7 @@ use self::newline_style::apply_newline_style; use crate::comment::{CharClasses, FullCodeCharKind}; use crate::config::{Config, FileName, Verbosity}; use crate::formatting::generated::is_generated_file; +use crate::ignore_path::IgnorePathSet; use crate::modules::Module; use crate::parse::parser::{DirectoryOwnership, Parser, ParserError}; use crate::parse::session::ParseSess; @@ -36,6 +39,15 @@ impl<'b, T: Write + 'b> Session<'b, T> { return Err(ErrorKind::VersionMismatch); } + let cargo_toml = Some(OsStr::new("Cargo.toml")); + match input { + Input::File(path) if path.file_name() == cargo_toml => { + let config = &self.config.clone(); + return format_cargo_toml(path, config, self); + } + _ => {} + } + rustc_span::create_session_if_not_set_then(self.config.edition().into(), |_| { if self.config.disable_all_formatting() { // When the input is from stdin, echo back the input. @@ -175,6 +187,29 @@ fn format_project( Ok(context.report) } +fn format_cargo_toml( + path: PathBuf, + config: &Config, + handler: &mut T, +) -> Result { + let mut report = FormatReport::new(); + + let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore())?; + let file_name = FileName::Real(path.clone()); + if ignore_path_set.is_match(&file_name) { + return Ok(report); + } + + let input = std::fs::read_to_string(&path)?; + let mut result = cargo_toml::format_cargo_toml_inner(&input, config)?; + + apply_newline_style(config.newline_style(), &mut result, &input); + + handler.handle_formatted_file(None, file_name, result, &mut report)?; + + Ok(report) +} + // Used for formatting files. #[derive(new)] struct FormatContext<'a, T: FormatHandler> { @@ -242,7 +277,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { .add_non_formatted_ranges(visitor.skipped_range.borrow().clone()); self.handler.handle_formatted_file( - &self.parse_session, + Some(&self.parse_session), path, visitor.buffer.to_owned(), &mut self.report, @@ -254,7 +289,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { trait FormatHandler { fn handle_formatted_file( &mut self, - parse_session: &ParseSess, + parse_session: Option<&ParseSess>, path: FileName, result: String, report: &mut FormatReport, @@ -265,14 +300,14 @@ impl<'b, T: Write + 'b> FormatHandler for Session<'b, T> { // Called for each formatted file. fn handle_formatted_file( &mut self, - parse_session: &ParseSess, + parse_session: Option<&ParseSess>, path: FileName, result: String, report: &mut FormatReport, ) -> Result<(), ErrorKind> { if let Some(ref mut out) = self.out { match source_file::write_file( - Some(parse_session), + parse_session, &path, &result, out, diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index d3ec970d402..909cef9eb11 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -1,12 +1,13 @@ use itertools::Itertools; use std::cmp::Ordering; -use toml_edit::{visit_mut::*, Decor, Document, Formatted, Item, KeyMut, Table, TableLike, Value}; +use toml_edit::{ + visit_mut::*, Decor, Document, Formatted, Item, KeyMut, Table, TableLike, TomlError, Value, +}; -use crate::Config; +use crate::{Config, ErrorKind}; -#[allow(dead_code)] -fn format_cargo_toml(content: &str, config: &Config) -> String { - let mut doc = content.parse::().unwrap(); +pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result { + let mut doc = content.parse::()?; let rules: Vec> = vec![ Box::new(SortSection { current_position: 0, @@ -27,7 +28,14 @@ fn format_cargo_toml(content: &str, config: &Config) -> String { for mut rule in rules.into_iter() { rule.visit_document_mut(&mut doc); } - return doc.to_string(); + + Ok(doc.to_string()) +} + +impl From for ErrorKind { + fn from(_: TomlError) -> Self { + ErrorKind::ParseError + } } /// Sort key names alphabetically within each section, with the exception of the @@ -363,7 +371,7 @@ mod tests { d = "git-rustfmt" c = "src/git-rustfmt/main.rs""#; - let formatted = format_cargo_toml(s, &Default::default()); + let formatted = format_cargo_toml_inner(s, &Default::default()).unwrap(); #[rustfmt::skip] let expected = r#"[package] From 784bb0554bfae069057e9dfdef6b4db4858d1e63 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 16 Jul 2022 11:42:19 +0200 Subject: [PATCH 05/24] remove debug things --- src/formatting/cargo_toml.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 909cef9eb11..34f861ee310 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -296,7 +296,6 @@ impl VisitMut for FormatInlineTable { let mut long_tables = vec![]; std::mem::swap(&mut self.long_tables, &mut long_tables); - println!("\n\n long tables\n {:?}\n\n", long_tables); long_tables.into_iter().for_each(|(section, key, table)| { match table { Item::Value(Value::InlineTable(table)) => { @@ -324,7 +323,6 @@ impl VisitMut for FormatInlineTable { long_table_keys.into_iter().for_each(|key| { let item = table.remove(&key).unwrap(); - println!("removed long item {:?}", item); self.long_tables .push((self.current_section.clone(), key, item)); }); @@ -406,7 +404,6 @@ path = "extremely_long_path_name_goes_right_here" version = "4.5.6" "#; - println!("{}", formatted); assert_eq!(formatted, expected); } } From baf8fa673f06b3835d61bfa25fb7376a04561400 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 16 Jul 2022 11:45:54 +0200 Subject: [PATCH 06/24] fmt --- src/formatting/cargo_toml.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 34f861ee310..9efe407bd43 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -296,15 +296,14 @@ impl VisitMut for FormatInlineTable { let mut long_tables = vec![]; std::mem::swap(&mut self.long_tables, &mut long_tables); - long_tables.into_iter().for_each(|(section, key, table)| { - match table { + long_tables + .into_iter() + .for_each(|(section, key, table)| match table { Item::Value(Value::InlineTable(table)) => { - // let table = format!("[{}]\n{}",key,table).parse::
().unwrap(); doc[§ion][&key] = Item::Table(table.into_table()); } _ => unreachable!(), - } - }); + }); } fn visit_table_like_mut(&mut self, table: &mut dyn TableLike) { From f188f1d8d56b67d3ce9238e4bba7df2fb0f70075 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 16 Jul 2022 11:51:50 +0200 Subject: [PATCH 07/24] use [&mut dyn] for rules --- src/formatting/cargo_toml.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 9efe407bd43..6b9f2111ca0 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -8,22 +8,22 @@ use crate::{Config, ErrorKind}; pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result { let mut doc = content.parse::()?; - let rules: Vec> = vec![ - Box::new(SortSection { + let rules = [ + &mut SortSection { current_position: 0, - }), - Box::new(SortKey), - Box::new(BlankLine { trimming: true }), - Box::new(KeyValue), - Box::new(MultiLine), - Box::new(WrapArray { + } as &mut dyn VisitMut, + &mut SortKey, + &mut BlankLine { trimming: true }, + &mut KeyValue, + &mut MultiLine, + &mut WrapArray { max_width: config.max_width(), - }), - Box::new(FormatInlineTable { + }, + &mut FormatInlineTable { max_width: config.max_width(), long_tables: vec![], current_section: String::new(), - }), + }, ]; for mut rule in rules.into_iter() { rule.visit_document_mut(&mut doc); From 30edae87769deae01e356a2da1db13fb61797b15 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 16 Jul 2022 12:02:39 +0200 Subject: [PATCH 08/24] fix --- src/formatting/cargo_toml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 6b9f2111ca0..f9ad8744bc6 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -25,7 +25,7 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< current_section: String::new(), }, ]; - for mut rule in rules.into_iter() { + for rule in rules.into_iter() { rule.visit_document_mut(&mut doc); } From beda3109c89adc30fc1d005581b9045b0c35f1e4 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sun, 24 Jul 2022 23:21:07 +0200 Subject: [PATCH 09/24] self apply --- Cargo.toml | 25 ++++++++----------- config_proc_macro/Cargo.toml | 6 ++--- src/formatting/cargo_toml.rs | 3 +++ .../test-submodule-issue-5119/Cargo.toml | 1 - 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f78a9453813..794fb882771 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,13 @@ [package] - name = "rustfmt-nightly" version = "1.5.1" -description = "Tool to find and fix Rust formatting issues" -repository = "https://github.com/rust-lang/rustfmt" -readme = "README.md" -license = "Apache-2.0/MIT" build = "build.rs" categories = ["development-tools"] edition = "2021" +license = "Apache-2.0/MIT" +readme = "README.md" +repository = "https://github.com/rust-lang/rustfmt" +description = "Tool to find and fix Rust formatting issues" [[bin]] name = "rustfmt" @@ -27,10 +26,10 @@ name = "git-rustfmt" path = "src/git-rustfmt/main.rs" [features] -default = ["cargo-fmt", "rustfmt-format-diff"] cargo-fmt = [] -rustfmt-format-diff = [] +default = ["cargo-fmt", "rustfmt-format-diff"] generic-simd = ["bytecount/generic-simd"] +rustfmt-format-diff = [] [dependencies] annotate-snippets = { version = "0.9", features = ["color"] } @@ -48,6 +47,11 @@ itertools = "0.10" lazy_static = "1.4" log = "0.4" regex = "1.5" +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" +rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" term = "0.7" @@ -58,13 +62,6 @@ unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" -rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } - -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. -rustc-workspace-hack = "1.0.0" - # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. [package.metadata.rust-analyzer] diff --git a/config_proc_macro/Cargo.toml b/config_proc_macro/Cargo.toml index d10d0469cc4..1f969edaa25 100644 --- a/config_proc_macro/Cargo.toml +++ b/config_proc_macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "rustfmt-config_proc_macro" version = "0.3.0" +categories = ["development-tools::procedural-macro-helpers"] edition = "2018" -description = "A collection of procedural macros for rustfmt" license = "Apache-2.0/MIT" -categories = ["development-tools::procedural-macro-helpers"] repository = "https://github.com/rust-lang/rustfmt" +description = "A collection of procedural macros for rustfmt" [lib] proc-macro = true @@ -19,5 +19,5 @@ syn = { version = "1.0", features = ["full", "visit"] } serde = { version = "1.0", features = ["derive"] } [features] -default = [] debug-with-rustfmt = [] +default = [] diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index f9ad8744bc6..d6e6eecab5c 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -6,6 +6,9 @@ use toml_edit::{ use crate::{Config, ErrorKind}; +/// Format `Cargo.toml` according to [the Style Guide] +/// +/// [the Style Guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/cargo.md). pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result { let mut doc = content.parse::()?; let rules = [ diff --git a/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml b/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml index 0993f127959..cbdde9fb0f1 100644 --- a/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml +++ b/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml @@ -4,5 +4,4 @@ version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] From 71609c512de99cd8a7f7ef9fc0cb711cc477382c Mon Sep 17 00:00:00 2001 From: xxchan Date: Mon, 25 Jul 2022 00:00:44 +0200 Subject: [PATCH 10/24] move test to integration test --- src/formatting/cargo_toml.rs | 75 ---------------------------- src/test/mod.rs | 9 ++-- tests/source/cargo-toml/1/Cargo.toml | 27 ++++++++++ tests/target/cargo-toml/1/Cargo.toml | 30 +++++++++++ 4 files changed, 63 insertions(+), 78 deletions(-) create mode 100644 tests/source/cargo-toml/1/Cargo.toml create mode 100644 tests/target/cargo-toml/1/Cargo.toml diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index d6e6eecab5c..3a0576fef1d 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -334,78 +334,3 @@ impl VisitMut for FormatInlineTable { }); } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn cargo_toml() { - #[rustfmt::skip] - let s = r#" - - -[[bin]] - "aa" = 1 - 'bb' = 2 - "啊"=1 -[package] - version = 1 - description = "a\nb\nhaha" - name = 3 - -# comment 1 - - arr1 = [1, - 2,3] - -# comment 2 - - arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] - -[dependencies] - extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} - crate1 = { path = "crate1",version = "1.2.3" } - -[[bin]] - d = "git-rustfmt" - c = "src/git-rustfmt/main.rs""#; - - let formatted = format_cargo_toml_inner(s, &Default::default()).unwrap(); - - #[rustfmt::skip] - let expected = r#"[package] -name = 3 -version = 1 -# comment 1 -arr1 = [1, 2, 3] -# comment 2 -arr2 = [ - "11111111111111111111111111111111111111111111111111111111111111111111111111111111", - "1111111111111111111111111111111111111111111111111111111111111111111111111111111" -] -description = """ -a -b -haha""" - -[[bin]] -aa = 1 -bb = 2 -"啊" = 1 - -[[bin]] -c = "src/git-rustfmt/main.rs" -d = "git-rustfmt" - -[dependencies] -crate1 = { path = "crate1", version = "1.2.3" } - -[dependencies.extremely_long_crate_name_goes_here] -path = "extremely_long_path_name_goes_right_here" -version = "4.5.6" -"#; - - assert_eq!(formatted, expected); - } -} diff --git a/src/test/mod.rs b/src/test/mod.rs index cfad4a8ed0e..c827f229de4 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -95,8 +95,8 @@ fn is_file_skip(path: &Path) -> bool { .any(|file_path| is_subpath(path, file_path)) } -// Returns a `Vec` containing `PathBuf`s of files with an `rs` extension in the -// given path. The `recursive` argument controls if files from subdirectories +// Returns a `Vec` containing `PathBuf`s of files with an `rs` extension or a `Cargo.toml` filename +// in the given path. The `recursive` argument controls if files from subdirectories // are also returned. fn get_test_files(path: &Path, recursive: bool) -> Vec { let mut files = vec![]; @@ -109,7 +109,10 @@ fn get_test_files(path: &Path, recursive: bool) -> Vec { let path = entry.path(); if path.is_dir() && recursive { files.append(&mut get_test_files(&path, recursive)); - } else if path.extension().map_or(false, |f| f == "rs") && !is_file_skip(&path) { + } else if (path.extension().map_or(false, |f| f == "rs") + || path.file_name().map_or(false, |f| f == "Cargo.toml")) + && !is_file_skip(&path) + { files.push(path); } } diff --git a/tests/source/cargo-toml/1/Cargo.toml b/tests/source/cargo-toml/1/Cargo.toml new file mode 100644 index 00000000000..3343640bc93 --- /dev/null +++ b/tests/source/cargo-toml/1/Cargo.toml @@ -0,0 +1,27 @@ + + +[[bin]] + "aa" = 1 + 'bb' = 2 + "啊"=1 +[package] + version = 1 + description = "a\nb\nhaha" + name = 3 + +# comment 1 + + arr1 = [1, + 2,3] + +# comment 2 + + arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] + +[dependencies] + extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} + crate1 = { path = "crate1",version = "1.2.3" } + +[[bin]] + d = "git-rustfmt" + c = "src/git-rustfmt/main.rs" \ No newline at end of file diff --git a/tests/target/cargo-toml/1/Cargo.toml b/tests/target/cargo-toml/1/Cargo.toml new file mode 100644 index 00000000000..75ee67a4d75 --- /dev/null +++ b/tests/target/cargo-toml/1/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = 3 +version = 1 +# comment 1 +arr1 = [1, 2, 3] +# comment 2 +arr2 = [ + "11111111111111111111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111111111111111111" +] +description = """ +a +b +haha""" + +[[bin]] +aa = 1 +bb = 2 +"啊" = 1 + +[[bin]] +c = "src/git-rustfmt/main.rs" +d = "git-rustfmt" + +[dependencies] +crate1 = { path = "crate1", version = "1.2.3" } + +[dependencies.extremely_long_crate_name_goes_here] +path = "extremely_long_path_name_goes_right_here" +version = "4.5.6" From 2cb56ee013f6da8afcdfbd8aaee58fa9b5e8303f Mon Sep 17 00:00:00 2001 From: xxchan Date: Mon, 25 Jul 2022 00:04:53 +0200 Subject: [PATCH 11/24] typo --- src/formatting/cargo_toml.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 3a0576fef1d..50291040a4a 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -6,9 +6,9 @@ use toml_edit::{ use crate::{Config, ErrorKind}; -/// Format `Cargo.toml` according to [the Style Guide] +/// Format `Cargo.toml` according to [the Style Guide]. /// -/// [the Style Guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/cargo.md). +/// [the Style Guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/cargo.md pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result { let mut doc = content.parse::()?; let rules = [ From 77ad49f3ff24696c1d98a9eda16beaf80751223c Mon Sep 17 00:00:00 2001 From: xxchan Date: Mon, 25 Jul 2022 01:27:31 +0200 Subject: [PATCH 12/24] don't panic --- src/format_report_formatter.rs | 3 +++ src/formatting/cargo_toml.rs | 25 ++++++++++++++++++++----- src/lib.rs | 2 ++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/format_report_formatter.rs b/src/format_report_formatter.rs index fd536d4df41..79dfe8da684 100644 --- a/src/format_report_formatter.rs +++ b/src/format_report_formatter.rs @@ -146,5 +146,8 @@ fn error_kind_to_snippet_annotation_type(error_kind: &ErrorKind) -> AnnotationTy | ErrorKind::InvalidGlobPattern(_) | ErrorKind::VersionMismatch => AnnotationType::Error, ErrorKind::DeprecatedAttr => AnnotationType::Warning, + ErrorKind::CargoTomlError(_) => { + unreachable!("Cargo.toml formatting error is not contained in FormatReport.") + } } } diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 50291040a4a..8bc31058127 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -15,7 +15,6 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< &mut SortSection { current_position: 0, } as &mut dyn VisitMut, - &mut SortKey, &mut BlankLine { trimming: true }, &mut KeyValue, &mut MultiLine, @@ -31,13 +30,19 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< for rule in rules.into_iter() { rule.visit_document_mut(&mut doc); } + // Special handling for falliable rules. + let mut rule = SortKey { error: None }; + rule.visit_document_mut(&mut doc); + if let Some(e) = rule.error { + return Err(e); + } Ok(doc.to_string()) } impl From for ErrorKind { - fn from(_: TomlError) -> Self { - ErrorKind::ParseError + fn from(e: TomlError) -> Self { + ErrorKind::CargoTomlError(format!("{e}")) } } @@ -48,7 +53,9 @@ impl From for ErrorKind { /// put the `name` and `version` keys in that order at the top of that section, /// followed by the remaining keys other than `description` in alphabetical order, /// followed by the `description` at the end of that section. -struct SortKey; +struct SortKey { + error: Option, +} /// Put the `[package]` section at the top of the file struct SortSection { @@ -119,7 +126,15 @@ impl VisitMut for SortKey { fn visit_document_mut(&mut self, doc: &mut Document) { doc.as_table_mut().iter_mut().for_each(|(key, section)| { if key == "package" { - let table = section.as_table_mut().expect("package should be a table"); + let table = match section.as_table_mut() { + Some(table) => table, + None => { + self.error = Some(ErrorKind::CargoTomlError( + "package should be a table".into(), + )); + return; + } + }; // "name" is the first, "version" is the second, "description" is the last // everything else is sorted alphabetically table.sort_values_by(|k1, _, k2, _| match (k1.get(), k2.get()) { diff --git a/src/lib.rs b/src/lib.rs index 495010a297d..d4e31ea88ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,6 +133,8 @@ pub enum ErrorKind { /// Invalid glob pattern in `ignore` configuration option. #[error("Invalid glob pattern found in ignore list: {0}")] InvalidGlobPattern(ignore::Error), + #[error("Error when formatting Cargo.toml: {0}")] + CargoTomlError(String), } impl ErrorKind { From 835eb39c69d6e20f7d18a46e1402b68aa20e95dc Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 6 Aug 2022 00:22:55 +0300 Subject: [PATCH 13/24] add TrimSpaces & tests --- Cargo.toml | 1 - src/formatting/cargo_toml.rs | 99 +++++++++++++++++++ .../source/cargo-toml/{1 => basic}/Cargo.toml | 38 +++++-- .../cargo-toml/virtual-manifest/Cargo.toml | 39 ++++++++ .../target/cargo-toml/{1 => basic}/Cargo.toml | 15 ++- .../cargo-toml/virtual-manifest/Cargo.toml | 23 +++++ 6 files changed, 202 insertions(+), 13 deletions(-) rename tests/source/cargo-toml/{1 => basic}/Cargo.toml (51%) create mode 100644 tests/source/cargo-toml/virtual-manifest/Cargo.toml rename tests/target/cargo-toml/{1 => basic}/Cargo.toml (59%) create mode 100644 tests/target/cargo-toml/virtual-manifest/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 794fb882771..8bec51b1e8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,6 @@ unicode-width = "0.1" unicode_categories = "0.1" # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. - [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] rustc_private = true diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 8bc31058127..2c47bd0513f 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -26,6 +26,7 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< long_tables: vec![], current_section: String::new(), }, + &mut TrimSpaces, ]; for rule in rules.into_iter() { rule.visit_document_mut(&mut doc); @@ -75,6 +76,11 @@ struct BlankLine { trimming: bool, } +/// Trim unnecessary spaces. +/// +/// Note: this is not included in the Style Guide. +struct TrimSpaces; + /// Don't use quotes around any standard key names; use bare keys. Only use quoted /// keys for non-standard keys whose names require them, and avoid introducing such /// key names when possible. @@ -349,3 +355,96 @@ impl VisitMut for FormatInlineTable { }); } } + +impl TrimSpaces { + fn trim_block(s: &str) -> String { + let s = s.trim(); + if s.is_empty() { + return String::new(); + } + + let s: String = s + .lines() + .into_iter() + .filter_map(|line| { + let trimmed = line.trim(); + if trimmed.is_empty() { + None + } else { + Some(format!("{trimmed}")) + } + }) + .join("\n"); + + format!("{}\n", s) + } + + fn trim_suffix(s: &str) -> String { + let s = s.trim(); + if s.is_empty() { + String::new() + } else { + format!(" {}", s) + } + } +} + +impl VisitMut for TrimSpaces { + fn visit_document_mut(&mut self, node: &mut Document) { + self.visit_table_mut(node); + + let set_prefix = |decor: &mut Decor, i: usize| { + let prefix = format!( + "{}{}", + if i == 0 { "" } else { "\n" }, + Self::trim_block(decor.prefix().unwrap_or_default()) + ); + decor.set_prefix(prefix); + }; + let table = node.as_table_mut(); + for (i, (_, item)) in table.iter_mut().enumerate() { + if let Some(table) = item.as_table_mut() { + set_prefix(table.decor_mut(), i); + } else if let Some(arr) = item.as_array_of_tables_mut() { + for table in arr.iter_mut() { + set_prefix(table.decor_mut(), i); + } + } + } + + if !node.trailing().trim().is_empty() { + let trailing: String = Self::trim_block(node.trailing()); + node.set_trailing(&format!("\n{trailing}")); + } else { + node.set_trailing(""); + } + } + + fn visit_table_mut(&mut self, node: &mut Table) { + let decor = node.decor_mut(); + if let Some(prefix) = decor.prefix() { + decor.set_prefix(format!("\n{}", Self::trim_block(prefix))); + } + if let Some(suffix) = decor.suffix() { + decor.set_suffix(Self::trim_suffix(suffix)); + } + + self.visit_table_like_mut(node); + } + + fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { + let decor = key.decor_mut(); + if let Some(prefix) = decor.prefix() { + decor.set_prefix(format!("{}", Self::trim_block(prefix))); + } + + if let Some(value) = value.as_value_mut() { + let decor = value.decor_mut(); + if let Some(suffix) = decor.suffix() { + decor.set_suffix(Self::trim_suffix(suffix)); + } + } + + self.visit_item_mut(value); + } +} diff --git a/tests/source/cargo-toml/1/Cargo.toml b/tests/source/cargo-toml/basic/Cargo.toml similarity index 51% rename from tests/source/cargo-toml/1/Cargo.toml rename to tests/source/cargo-toml/basic/Cargo.toml index 3343640bc93..a321104d8fe 100644 --- a/tests/source/cargo-toml/1/Cargo.toml +++ b/tests/source/cargo-toml/basic/Cargo.toml @@ -1,27 +1,49 @@ -[[bin]] - "aa" = 1 - 'bb' = 2 + # comment before [[bin]], not necessarily at the beginning + + + [[bin]] # comment after [[bin]] + "aa" = 1 # comment for "aa" + 'bb' = 2 "啊"=1 + + # comment before package + [package] version = 1 description = "a\nb\nhaha" name = 3 -# comment 1 - + # comment 1 for arr1 line1 + +# comment 1 for arr1 line 2 arr1 = [1, - 2,3] + 2,3] -# comment 2 +# comment 2 for arr2 arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] + # comment before [[dependencies]], not after [package] + + [dependencies] extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} + + crate1 = { path = "crate1",version = "1.2.3" } + +# comment before the second [[bin]] [[bin]] d = "git-rustfmt" - c = "src/git-rustfmt/main.rs" \ No newline at end of file + c = "src/git-rustfmt/main.rs" + + + + + # comment at the end of the file + + + \ No newline at end of file diff --git a/tests/source/cargo-toml/virtual-manifest/Cargo.toml b/tests/source/cargo-toml/virtual-manifest/Cargo.toml new file mode 100644 index 00000000000..a1ebaddc3e5 --- /dev/null +++ b/tests/source/cargo-toml/virtual-manifest/Cargo.toml @@ -0,0 +1,39 @@ + + + # Works correctly for Cargo.toml without [package] + + +[workspace] + + +members = ["xtask/", "lib/*", "crates/*"] +exclude = ["crates/proc-macro-test/imp"] + + +[profile.dev] + +# Disabling debug info speeds up builds a bunch, +# and we don't rely on it for debugging that much. + +debug1 = 0 + + +[profile.dev.package] + +# These speed up local tests. +rowan.opt-level = 3 +rustc-hash.opt-level = 3 +smol_str.opt-level = 3 +text-size.opt-level = 3 +# This speeds up `cargo xtask dist`. +miniz_oxide.opt-level = 3 + + +[profile.release] + +incremental = true +# Set this to 1 or 2 to get more useful backtraces in debugger. +debug2 = 0 + + + \ No newline at end of file diff --git a/tests/target/cargo-toml/1/Cargo.toml b/tests/target/cargo-toml/basic/Cargo.toml similarity index 59% rename from tests/target/cargo-toml/1/Cargo.toml rename to tests/target/cargo-toml/basic/Cargo.toml index 75ee67a4d75..3052e6d4a4e 100644 --- a/tests/target/cargo-toml/1/Cargo.toml +++ b/tests/target/cargo-toml/basic/Cargo.toml @@ -1,9 +1,11 @@ +# comment before package [package] name = 3 version = 1 -# comment 1 +# comment 1 for arr1 line1 +# comment 1 for arr1 line 2 arr1 = [1, 2, 3] -# comment 2 +# comment 2 for arr2 arr2 = [ "11111111111111111111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111111111111111111111111" @@ -13,18 +15,23 @@ a b haha""" -[[bin]] -aa = 1 +# comment before [[bin]], not necessarily at the beginning +[[bin]] # comment after [[bin]] +aa = 1 # comment for "aa" bb = 2 "啊" = 1 +# comment before the second [[bin]] [[bin]] c = "src/git-rustfmt/main.rs" d = "git-rustfmt" +# comment before [[dependencies]], not after [package] [dependencies] crate1 = { path = "crate1", version = "1.2.3" } [dependencies.extremely_long_crate_name_goes_here] path = "extremely_long_path_name_goes_right_here" version = "4.5.6" + +# comment at the end of the file diff --git a/tests/target/cargo-toml/virtual-manifest/Cargo.toml b/tests/target/cargo-toml/virtual-manifest/Cargo.toml new file mode 100644 index 00000000000..ca0ae7b49bb --- /dev/null +++ b/tests/target/cargo-toml/virtual-manifest/Cargo.toml @@ -0,0 +1,23 @@ +# Works correctly for Cargo.toml without [package] +[workspace] +exclude = ["crates/proc-macro-test/imp"] +members = ["xtask/", "lib/*", "crates/*"] + +[profile.dev] +# Disabling debug info speeds up builds a bunch, +# and we don't rely on it for debugging that much. +debug1 = 0 + +[profile.dev.package] +# These speed up local tests. +rowan.opt-level = 3 +rustc-hash.opt-level = 3 +smol_str.opt-level = 3 +text-size.opt-level = 3 +# This speeds up `cargo xtask dist`. +miniz_oxide.opt-level = 3 + +[profile.release] +incremental = true +# Set this to 1 or 2 to get more useful backtraces in debugger. +debug2 = 0 From 02df831773c713830570bcec35872b57b0f4a51e Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 6 Aug 2022 10:47:35 +0300 Subject: [PATCH 14/24] test key with many dots --- src/formatting/cargo_toml.rs | 25 ++++++++---- tests/source/cargo-toml/dotted-key/Cargo.toml | 38 +++++++++++++++++++ tests/target/cargo-toml/dotted-key/Cargo.toml | 33 ++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 tests/source/cargo-toml/dotted-key/Cargo.toml create mode 100644 tests/target/cargo-toml/dotted-key/Cargo.toml diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 2c47bd0513f..729fdcdccb4 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -24,7 +24,7 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< &mut FormatInlineTable { max_width: config.max_width(), long_tables: vec![], - current_section: String::new(), + current_section: vec![], }, &mut TrimSpaces, ]; @@ -124,8 +124,8 @@ struct WrapArray { struct FormatInlineTable { max_width: usize, /// Must be `InlineTable` - long_tables: Vec<(String, String, Item)>, - current_section: String, + long_tables: Vec<(Vec, String, Item)>, + current_section: Vec, } impl VisitMut for SortKey { @@ -279,6 +279,9 @@ impl VisitMut for SortSection { fn visit_table_mut(&mut self, table: &mut Table) { table.set_position(self.current_position); self.current_position += 1; + for (_, v) in table.iter_mut().sorted_by_key(|(k, _)| k.to_string()) { + self.visit_item_mut(v); + } } } @@ -313,7 +316,7 @@ impl VisitMut for WrapArray { impl VisitMut for FormatInlineTable { fn visit_document_mut(&mut self, doc: &mut Document) { doc.as_table_mut().iter_mut().for_each(|(key, section)| { - self.current_section = key.to_owned(); + self.current_section = vec![key.to_owned()]; self.visit_table_like_kv_mut(key, section); }); @@ -322,9 +325,13 @@ impl VisitMut for FormatInlineTable { long_tables .into_iter() - .for_each(|(section, key, table)| match table { + .for_each(|(sections, key, table)| match table { Item::Value(Value::InlineTable(table)) => { - doc[§ion][&key] = Item::Table(table.into_table()); + let mut section = doc.as_item_mut(); + for key in sections { + section = &mut section[&key] + } + section[&key] = Item::Table(table.into_table()); } _ => unreachable!(), }); @@ -344,14 +351,16 @@ impl VisitMut for FormatInlineTable { } }); - long_table_keys.into_iter().for_each(|key| { + long_table_keys.into_iter().sorted().for_each(|key| { let item = table.remove(&key).unwrap(); self.long_tables .push((self.current_section.clone(), key, item)); }); - table.iter_mut().for_each(|(_, node)| { + table.iter_mut().for_each(|(key, node)| { + self.current_section.push(key.to_owned()); self.visit_item_mut(node); + self.current_section.pop(); }); } } diff --git a/tests/source/cargo-toml/dotted-key/Cargo.toml b/tests/source/cargo-toml/dotted-key/Cargo.toml new file mode 100644 index 00000000000..d834d80c568 --- /dev/null +++ b/tests/source/cargo-toml/dotted-key/Cargo.toml @@ -0,0 +1,38 @@ + + [a.c] + ac =1 + + # comment for [a.a] + + [a.a] # also comment for [a.a] + aa=1 + + # comment for [a.a.c.d] + +[a.a.c.d] +aacd=1 + +[a.a.b] +veryveryveryveryveryveryveryverylong-table-name2={veryveryveryveryveryveryveryverylong-key-name=2} + aab =1 + +veryveryveryveryveryveryveryverylong-table-name={veryveryveryveryveryveryveryverylong-key-name=1} + +[a.a.c] +aac=1 + + + [a] + +# comment for [a.b], not [a.b.b] +b.b = 1 + + # comment for cc + cc = 3 + + +b.a = 2 + + + [a.z] + az=1 \ No newline at end of file diff --git a/tests/target/cargo-toml/dotted-key/Cargo.toml b/tests/target/cargo-toml/dotted-key/Cargo.toml new file mode 100644 index 00000000000..1ef5d951081 --- /dev/null +++ b/tests/target/cargo-toml/dotted-key/Cargo.toml @@ -0,0 +1,33 @@ +[a] +# comment for [a.b], not [a.b.b] +b.a = 2 +# comment for [a.b], not [a.b.b] +b.b = 1 +# comment for cc +cc = 3 + +# comment for [a.a] +[a.a] # also comment for [a.a] +aa = 1 + +[a.a.b] +aab = 1 + +[a.a.b.veryveryveryveryveryveryveryverylong-table-name] +veryveryveryveryveryveryveryverylong-key-name = 1 + +[a.a.b.veryveryveryveryveryveryveryverylong-table-name2] +veryveryveryveryveryveryveryverylong-key-name = 2 + +[a.a.c] +aac = 1 + +# comment for [a.a.c.d] +[a.a.c.d] +aacd = 1 + +[a.c] +ac = 1 + +[a.z] +az = 1 From 3dc6d27463f70dd2ab65c8528a5c0dadeeb03bdb Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 12 Nov 2022 12:25:26 +0100 Subject: [PATCH 15/24] add format_cargo_toml option & integrate to cargo-fmt --- Cargo.toml | 10 ++++---- Configurations.md | 8 +++++++ rustfmt.toml | 1 + src/cargo-fmt/main.rs | 45 +++++++++++++++++++++++++++++++---- src/cargo-fmt/test/targets.rs | 4 ++-- src/config/mod.rs | 2 ++ src/formatting.rs | 2 +- src/test/mod.rs | 6 +++++ 8 files changed, 65 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8bec51b1e8c..c9fbcdba7fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,11 @@ readme = "README.md" repository = "https://github.com/rust-lang/rustfmt" description = "Tool to find and fix Rust formatting issues" +# Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. +[package.metadata.rust-analyzer] +# This package uses #[feature(rustc_private)] +rustc_private = true + [[bin]] name = "rustfmt" path = "src/bin/main.rs" @@ -61,8 +66,3 @@ toml_edit = "0.13" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" - -# Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. -[package.metadata.rust-analyzer] -# This package uses #[feature(rustc_private)] -rustc_private = true diff --git a/Configurations.md b/Configurations.md index 49e7e4e6489..c100d296786 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1040,6 +1040,14 @@ fn add_one(x: i32) -> i32 { } ``` +## `format_cargo_toml` + +Format `Cargo.toml` files. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No (tracking issue: [#4091](https://github.com/rust-lang/rustfmt/issues/4091)) + ## `doc_comment_code_block_width` Max width for code snippets included in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true. diff --git a/rustfmt.toml b/rustfmt.toml index eccd5f9bd19..1f169d2a79b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ error_on_line_overflow = true error_on_unformatted = true version = "Two" +format_cargo_toml = true \ No newline at end of file diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index 2b714b68df0..9410e3fd175 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -284,6 +284,15 @@ impl Target { edition: target.edition.clone(), } } + + /// `Cargo.toml` file to format. + pub fn manifest_target(manifest_path: PathBuf) -> Self { + Target { + path: manifest_path, + kind: String::from("manifest"), + edition: String::from("2021"), // The value doesn't matter for formatting Cargo.toml. + } + } } impl PartialEq for Target { @@ -365,6 +374,9 @@ fn get_targets_root_only( ) -> Result<(), io::Error> { let metadata = get_cargo_metadata(manifest_path)?; let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?; + targets.insert(Target::manifest_target( + workspace_root_path.join("Cargo.toml"), + )); let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path { ( workspace_root_path == target_manifest, @@ -379,7 +391,15 @@ fn get_targets_root_only( }; let package_targets = match metadata.packages.len() { - 1 => metadata.packages.into_iter().next().unwrap().targets, + 1 => { + let p = metadata.packages.into_iter().next().unwrap(); + targets.insert(Target::manifest_target( + PathBuf::from(&p.manifest_path) + .canonicalize() + .unwrap_or_default(), + )); + p.targets + } _ => metadata .packages .into_iter() @@ -390,13 +410,18 @@ fn get_targets_root_only( .unwrap_or_default() == current_dir_manifest }) - .flat_map(|p| p.targets) + .flat_map(|p| { + targets.insert(Target::manifest_target( + PathBuf::from(&p.manifest_path) + .canonicalize() + .unwrap_or_default(), + )); + p.targets + }) .collect(), }; - for target in package_targets { - targets.insert(Target::from_target(&target)); - } + add_targets(&package_targets, targets); Ok(()) } @@ -408,6 +433,11 @@ fn get_targets_recursive( ) -> Result<(), io::Error> { let metadata = get_cargo_metadata(manifest_path)?; for package in &metadata.packages { + targets.insert(Target::manifest_target( + PathBuf::from(&package.manifest_path) + .canonicalize() + .unwrap_or_default(), + )); add_targets(&package.targets, targets); // Look for local dependencies using information available since cargo v1.51 @@ -447,6 +477,11 @@ fn get_targets_with_hitlist( for package in metadata.packages { if workspace_hitlist.remove(&package.name) { + targets.insert(Target::manifest_target( + PathBuf::from(&package.manifest_path) + .canonicalize() + .unwrap_or_default(), + )); for target in package.targets { targets.insert(Target::from_target(&target)); } diff --git a/src/cargo-fmt/test/targets.rs b/src/cargo-fmt/test/targets.rs index b7e7fabdf71..c0308c9e61a 100644 --- a/src/cargo-fmt/test/targets.rs +++ b/src/cargo-fmt/test/targets.rs @@ -57,7 +57,7 @@ mod all_targets { manifest_suffix, "divergent-crate-dir-names", &exp_targets, - 3, + 3 + 3, // include 3 Cargo.toml files ); } @@ -112,7 +112,7 @@ mod all_targets { manifest_suffix, "workspaces/path-dep-above", &exp_targets, - 6, + 6 + 6, // include 6 Cargo.toml files, ); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 14f27f3f8b6..8484d961c93 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -173,6 +173,7 @@ create_config! { or they are left with trailing whitespaces"; ignore: IgnoreList, IgnoreList::default(), false, "Skip formatting the specified files and directories"; + format_cargo_toml: bool, false, false, "Format Cargo.toml files"; // Not user-facing verbose: Verbosity, Verbosity::Normal, false, "How much to information to emit to the user"; @@ -681,6 +682,7 @@ hide_parse_errors = false error_on_line_overflow = false error_on_unformatted = false ignore = [] +format_cargo_toml = false emit_mode = "Files" make_backup = false "#, diff --git a/src/formatting.rs b/src/formatting.rs index 892c8d5132c..af460c0bd0c 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -196,7 +196,7 @@ fn format_cargo_toml( let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore())?; let file_name = FileName::Real(path.clone()); - if ignore_path_set.is_match(&file_name) { + if !config.format_cargo_toml() || ignore_path_set.is_match(&file_name) { return Ok(report); } diff --git a/src/test/mod.rs b/src/test/mod.rs index c827f229de4..b5398da640f 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -696,6 +696,12 @@ fn print_mismatches String>( } fn read_config(filename: &Path) -> Config { + if filename.file_name().map_or(false, |f| f == "Cargo.toml") { + let mut config = Config::default(); + config.set().format_cargo_toml(true); + return config; + } + let sig_comments = read_significant_comments(filename); // Look for a config file. If there is a 'config' property in the significant comments, use // that. Otherwise, if there are no significant comments at all, look for a config file with From 6ae3c97c170413ebf82f1af996837ec73862ca56 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 19 Nov 2022 23:40:42 +0100 Subject: [PATCH 16/24] revert formatting Cargo.toml on the repo --- Cargo.lock | 41 +++++++++---------- Cargo.toml | 38 +++++++++-------- config_proc_macro/Cargo.toml | 6 +-- rustfmt.toml | 1 - .../test-submodule-issue-5119/Cargo.toml | 1 + 5 files changed, 44 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5def1acd345..2a936001507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "camino" @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.3" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -279,9 +279,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -334,9 +334,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -347,15 +347,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" -[[package]] -name = "kstring" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526" -dependencies = [ - "serde", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -682,16 +673,22 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd" + [[package]] name = "toml_edit" -version = "0.13.4" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b" +checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646" dependencies = [ "combine", "indexmap", "itertools", - "kstring", + "toml_datetime", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c9fbcdba7fb..471a2763a0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,14 @@ [package] + name = "rustfmt-nightly" version = "1.5.1" +description = "Tool to find and fix Rust formatting issues" +repository = "https://github.com/rust-lang/rustfmt" +readme = "README.md" +license = "Apache-2.0/MIT" build = "build.rs" categories = ["development-tools"] edition = "2021" -license = "Apache-2.0/MIT" -readme = "README.md" -repository = "https://github.com/rust-lang/rustfmt" -description = "Tool to find and fix Rust formatting issues" - -# Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. -[package.metadata.rust-analyzer] -# This package uses #[feature(rustc_private)] -rustc_private = true [[bin]] name = "rustfmt" @@ -31,10 +27,10 @@ name = "git-rustfmt" path = "src/git-rustfmt/main.rs" [features] -cargo-fmt = [] default = ["cargo-fmt", "rustfmt-format-diff"] -generic-simd = ["bytecount/generic-simd"] +cargo-fmt = [] rustfmt-format-diff = [] +generic-simd = ["bytecount/generic-simd"] [dependencies] annotate-snippets = { version = "0.9", features = ["color"] } @@ -52,17 +48,25 @@ itertools = "0.10" lazy_static = "1.4" log = "0.4" regex = "1.5" -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. -rustc-workspace-hack = "1.0.0" -rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" term = "0.7" thiserror = "1.0" toml = "0.5" -toml_edit = "0.13" +toml_edit = "0.15" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" + +rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } + +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" + +# Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. + +[package.metadata.rust-analyzer] +# This package uses #[feature(rustc_private)] +rustc_private = true diff --git a/config_proc_macro/Cargo.toml b/config_proc_macro/Cargo.toml index 1f969edaa25..d10d0469cc4 100644 --- a/config_proc_macro/Cargo.toml +++ b/config_proc_macro/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "rustfmt-config_proc_macro" version = "0.3.0" -categories = ["development-tools::procedural-macro-helpers"] edition = "2018" +description = "A collection of procedural macros for rustfmt" license = "Apache-2.0/MIT" +categories = ["development-tools::procedural-macro-helpers"] repository = "https://github.com/rust-lang/rustfmt" -description = "A collection of procedural macros for rustfmt" [lib] proc-macro = true @@ -19,5 +19,5 @@ syn = { version = "1.0", features = ["full", "visit"] } serde = { version = "1.0", features = ["derive"] } [features] -debug-with-rustfmt = [] default = [] +debug-with-rustfmt = [] diff --git a/rustfmt.toml b/rustfmt.toml index 1f169d2a79b..eccd5f9bd19 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,3 @@ error_on_line_overflow = true error_on_unformatted = true version = "Two" -format_cargo_toml = true \ No newline at end of file diff --git a/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml b/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml index cbdde9fb0f1..0993f127959 100644 --- a/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml +++ b/tests/mod-resolver/test-submodule-issue-5119/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + [dependencies] From ffbb3bad8681f6d9dfb491ed55216bc055b0363b Mon Sep 17 00:00:00 2001 From: xxchan Date: Sat, 19 Nov 2022 23:50:48 +0100 Subject: [PATCH 17/24] add example in Configuration doc --- Configurations.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Configurations.md b/Configurations.md index c100d296786..03953d38ae4 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1042,12 +1042,42 @@ fn add_one(x: i32) -> i32 { ## `format_cargo_toml` -Format `Cargo.toml` files. +Format `Cargo.toml` files according to the [Cargo.toml conventions](https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/cargo.md). - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#4091](https://github.com/rust-lang/rustfmt/issues/4091)) +#### `false` (default): + +```toml + [package] +edition="2018" + +version="0.1.0" + name="e" +[dependencies] +a="0.1" + + +c="0.3" +b="0.2" +``` + +#### `true`: + +```toml +[package] +name = "e" +version = "0.1.0" +edition = "2018" + +[dependencies] +a = "0.1" +b = "0.2" +c = "0.3" +``` + ## `doc_comment_code_block_width` Max width for code snippets included in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true. From 56a2c30e168f6279cbe4b9f441378c71627eaf81 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sun, 20 Nov 2022 15:54:28 +0100 Subject: [PATCH 18/24] use significant comments to set format_cargo_toml: true --- src/test/mod.rs | 21 ++++---- tests/source/cargo-toml/false/Cargo.toml | 49 +++++++++++++++++++ .../cargo-toml/{ => true}/basic/Cargo.toml | 2 +- .../{ => true}/dotted-key/Cargo.toml | 1 + .../{ => true}/virtual-manifest/Cargo.toml | 1 + tests/target/cargo-toml/false/Cargo.toml | 49 +++++++++++++++++++ .../cargo-toml/{ => true}/basic/Cargo.toml | 1 + .../{ => true}/dotted-key/Cargo.toml | 1 + .../{ => true}/virtual-manifest/Cargo.toml | 1 + 9 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 tests/source/cargo-toml/false/Cargo.toml rename tests/source/cargo-toml/{ => true}/basic/Cargo.toml (96%) rename tests/source/cargo-toml/{ => true}/dotted-key/Cargo.toml (93%) rename tests/source/cargo-toml/{ => true}/virtual-manifest/Cargo.toml (94%) create mode 100644 tests/target/cargo-toml/false/Cargo.toml rename tests/target/cargo-toml/{ => true}/basic/Cargo.toml (96%) rename tests/target/cargo-toml/{ => true}/dotted-key/Cargo.toml (93%) rename tests/target/cargo-toml/{ => true}/virtual-manifest/Cargo.toml (94%) diff --git a/src/test/mod.rs b/src/test/mod.rs index b5398da640f..d63ab2ee105 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -696,12 +696,6 @@ fn print_mismatches String>( } fn read_config(filename: &Path) -> Config { - if filename.file_name().map_or(false, |f| f == "Cargo.toml") { - let mut config = Config::default(); - config.set().format_cargo_toml(true); - return config; - } - let sig_comments = read_significant_comments(filename); // Look for a config file. If there is a 'config' property in the significant comments, use // that. Otherwise, if there are no significant comments at all, look for a config file with @@ -794,15 +788,24 @@ fn get_config(config_file: Option<&Path>) -> Config { // Reads significant comments of the form: `// rustfmt-key: value` into a hash map. fn read_significant_comments(file_name: &Path) -> HashMap { + let is_cargo_toml = file_name.file_name().map_or(false, |f| f == "Cargo.toml"); let file = fs::File::open(file_name) .unwrap_or_else(|_| panic!("couldn't read file {}", file_name.display())); let reader = BufReader::new(file); - let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)"; + let pattern = if is_cargo_toml { + r"^\s*#\s*rustfmt-([^:]+):\s*(\S+)" + } else { + r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)" + }; let regex = regex::Regex::new(pattern).expect("failed creating pattern 1"); // Matches lines containing significant comments or whitespace. - let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)") - .expect("failed creating pattern 2"); + let line_regex = regex::Regex::new(if is_cargo_toml { + r"(^\s*$)|(^\s*#\s*rustfmt-[^:]+:\s*\S+)" + } else { + r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)" + }) + .expect("failed creating pattern 2"); reader .lines() diff --git a/tests/source/cargo-toml/false/Cargo.toml b/tests/source/cargo-toml/false/Cargo.toml new file mode 100644 index 00000000000..dc2dcf3ef11 --- /dev/null +++ b/tests/source/cargo-toml/false/Cargo.toml @@ -0,0 +1,49 @@ +# rustfmt-format_cargo_toml: false + + # comment before [[bin]], not necessarily at the beginning + + + [[bin]] # comment after [[bin]] + "aa" = 1 # comment for "aa" + 'bb' = 2 + "啊"=1 + + # comment before package + +[package] + version = 1 + description = "a\nb\nhaha" + name = 3 + + # comment 1 for arr1 line1 + +# comment 1 for arr1 line 2 + arr1 = [1, + 2,3] + +# comment 2 for arr2 + + arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] + + # comment before [[dependencies]], not after [package] + + +[dependencies] + extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} + + + crate1 = { path = "crate1",version = "1.2.3" } + +# comment before the second [[bin]] + +[[bin]] + d = "git-rustfmt" + c = "src/git-rustfmt/main.rs" + + + + + # comment at the end of the file + + + \ No newline at end of file diff --git a/tests/source/cargo-toml/basic/Cargo.toml b/tests/source/cargo-toml/true/basic/Cargo.toml similarity index 96% rename from tests/source/cargo-toml/basic/Cargo.toml rename to tests/source/cargo-toml/true/basic/Cargo.toml index a321104d8fe..377d79e50c2 100644 --- a/tests/source/cargo-toml/basic/Cargo.toml +++ b/tests/source/cargo-toml/true/basic/Cargo.toml @@ -1,4 +1,4 @@ - +# rustfmt-format_cargo_toml: true # comment before [[bin]], not necessarily at the beginning diff --git a/tests/source/cargo-toml/dotted-key/Cargo.toml b/tests/source/cargo-toml/true/dotted-key/Cargo.toml similarity index 93% rename from tests/source/cargo-toml/dotted-key/Cargo.toml rename to tests/source/cargo-toml/true/dotted-key/Cargo.toml index d834d80c568..fffe7d21ec1 100644 --- a/tests/source/cargo-toml/dotted-key/Cargo.toml +++ b/tests/source/cargo-toml/true/dotted-key/Cargo.toml @@ -1,3 +1,4 @@ +# rustfmt-format_cargo_toml: true [a.c] ac =1 diff --git a/tests/source/cargo-toml/virtual-manifest/Cargo.toml b/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml similarity index 94% rename from tests/source/cargo-toml/virtual-manifest/Cargo.toml rename to tests/source/cargo-toml/true/virtual-manifest/Cargo.toml index a1ebaddc3e5..0a74f24c777 100644 --- a/tests/source/cargo-toml/virtual-manifest/Cargo.toml +++ b/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml @@ -1,3 +1,4 @@ +# rustfmt-format_cargo_toml: true # Works correctly for Cargo.toml without [package] diff --git a/tests/target/cargo-toml/false/Cargo.toml b/tests/target/cargo-toml/false/Cargo.toml new file mode 100644 index 00000000000..dc2dcf3ef11 --- /dev/null +++ b/tests/target/cargo-toml/false/Cargo.toml @@ -0,0 +1,49 @@ +# rustfmt-format_cargo_toml: false + + # comment before [[bin]], not necessarily at the beginning + + + [[bin]] # comment after [[bin]] + "aa" = 1 # comment for "aa" + 'bb' = 2 + "啊"=1 + + # comment before package + +[package] + version = 1 + description = "a\nb\nhaha" + name = 3 + + # comment 1 for arr1 line1 + +# comment 1 for arr1 line 2 + arr1 = [1, + 2,3] + +# comment 2 for arr2 + + arr2 = ["11111111111111111111111111111111111111111111111111111111111111111111111111111111","1111111111111111111111111111111111111111111111111111111111111111111111111111111"] + + # comment before [[dependencies]], not after [package] + + +[dependencies] + extremely_long_crate_name_goes_here = {path = "extremely_long_path_name_goes_right_here",version = "4.5.6"} + + + crate1 = { path = "crate1",version = "1.2.3" } + +# comment before the second [[bin]] + +[[bin]] + d = "git-rustfmt" + c = "src/git-rustfmt/main.rs" + + + + + # comment at the end of the file + + + \ No newline at end of file diff --git a/tests/target/cargo-toml/basic/Cargo.toml b/tests/target/cargo-toml/true/basic/Cargo.toml similarity index 96% rename from tests/target/cargo-toml/basic/Cargo.toml rename to tests/target/cargo-toml/true/basic/Cargo.toml index 3052e6d4a4e..5733fabc2fb 100644 --- a/tests/target/cargo-toml/basic/Cargo.toml +++ b/tests/target/cargo-toml/true/basic/Cargo.toml @@ -15,6 +15,7 @@ a b haha""" +# rustfmt-format_cargo_toml: true # comment before [[bin]], not necessarily at the beginning [[bin]] # comment after [[bin]] aa = 1 # comment for "aa" diff --git a/tests/target/cargo-toml/dotted-key/Cargo.toml b/tests/target/cargo-toml/true/dotted-key/Cargo.toml similarity index 93% rename from tests/target/cargo-toml/dotted-key/Cargo.toml rename to tests/target/cargo-toml/true/dotted-key/Cargo.toml index 1ef5d951081..6d7597c7352 100644 --- a/tests/target/cargo-toml/dotted-key/Cargo.toml +++ b/tests/target/cargo-toml/true/dotted-key/Cargo.toml @@ -26,6 +26,7 @@ aac = 1 [a.a.c.d] aacd = 1 +# rustfmt-format_cargo_toml: true [a.c] ac = 1 diff --git a/tests/target/cargo-toml/virtual-manifest/Cargo.toml b/tests/target/cargo-toml/true/virtual-manifest/Cargo.toml similarity index 94% rename from tests/target/cargo-toml/virtual-manifest/Cargo.toml rename to tests/target/cargo-toml/true/virtual-manifest/Cargo.toml index ca0ae7b49bb..4302a93e4e5 100644 --- a/tests/target/cargo-toml/virtual-manifest/Cargo.toml +++ b/tests/target/cargo-toml/true/virtual-manifest/Cargo.toml @@ -1,3 +1,4 @@ +# rustfmt-format_cargo_toml: true # Works correctly for Cargo.toml without [package] [workspace] exclude = ["crates/proc-macro-test/imp"] From b0565d89e91b3f5908ac44a8cadaac4f116dabdc Mon Sep 17 00:00:00 2001 From: xxchan Date: Sun, 20 Nov 2022 15:57:01 +0100 Subject: [PATCH 19/24] a newline at the end of each file --- tests/source/cargo-toml/false/Cargo.toml | 1 - tests/source/cargo-toml/true/basic/Cargo.toml | 1 - tests/source/cargo-toml/true/dotted-key/Cargo.toml | 3 ++- tests/source/cargo-toml/true/virtual-manifest/Cargo.toml | 1 - tests/target/cargo-toml/false/Cargo.toml | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/source/cargo-toml/false/Cargo.toml b/tests/source/cargo-toml/false/Cargo.toml index dc2dcf3ef11..a0b4ad1164d 100644 --- a/tests/source/cargo-toml/false/Cargo.toml +++ b/tests/source/cargo-toml/false/Cargo.toml @@ -46,4 +46,3 @@ # comment at the end of the file - \ No newline at end of file diff --git a/tests/source/cargo-toml/true/basic/Cargo.toml b/tests/source/cargo-toml/true/basic/Cargo.toml index 377d79e50c2..9134c689785 100644 --- a/tests/source/cargo-toml/true/basic/Cargo.toml +++ b/tests/source/cargo-toml/true/basic/Cargo.toml @@ -46,4 +46,3 @@ # comment at the end of the file - \ No newline at end of file diff --git a/tests/source/cargo-toml/true/dotted-key/Cargo.toml b/tests/source/cargo-toml/true/dotted-key/Cargo.toml index fffe7d21ec1..ecc19768777 100644 --- a/tests/source/cargo-toml/true/dotted-key/Cargo.toml +++ b/tests/source/cargo-toml/true/dotted-key/Cargo.toml @@ -36,4 +36,5 @@ b.a = 2 [a.z] - az=1 \ No newline at end of file + az=1 + diff --git a/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml b/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml index 0a74f24c777..c065b63cead 100644 --- a/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml +++ b/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml @@ -37,4 +37,3 @@ incremental = true debug2 = 0 - \ No newline at end of file diff --git a/tests/target/cargo-toml/false/Cargo.toml b/tests/target/cargo-toml/false/Cargo.toml index dc2dcf3ef11..a0b4ad1164d 100644 --- a/tests/target/cargo-toml/false/Cargo.toml +++ b/tests/target/cargo-toml/false/Cargo.toml @@ -46,4 +46,3 @@ # comment at the end of the file - \ No newline at end of file From c17e2b9a8a85728cead7bb0043d60903a590c8f6 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sun, 20 Nov 2022 16:11:07 +0100 Subject: [PATCH 20/24] remove CargoTomlError --- src/format_report_formatter.rs | 3 --- src/formatting/cargo_toml.rs | 9 ++++----- src/lib.rs | 2 -- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/format_report_formatter.rs b/src/format_report_formatter.rs index 79dfe8da684..fd536d4df41 100644 --- a/src/format_report_formatter.rs +++ b/src/format_report_formatter.rs @@ -146,8 +146,5 @@ fn error_kind_to_snippet_annotation_type(error_kind: &ErrorKind) -> AnnotationTy | ErrorKind::InvalidGlobPattern(_) | ErrorKind::VersionMismatch => AnnotationType::Error, ErrorKind::DeprecatedAttr => AnnotationType::Warning, - ErrorKind::CargoTomlError(_) => { - unreachable!("Cargo.toml formatting error is not contained in FormatReport.") - } } } diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 729fdcdccb4..e1cb685c13d 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -42,8 +42,8 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< } impl From for ErrorKind { - fn from(e: TomlError) -> Self { - ErrorKind::CargoTomlError(format!("{e}")) + fn from(_: TomlError) -> Self { + ErrorKind::ParseError } } @@ -135,9 +135,8 @@ impl VisitMut for SortKey { let table = match section.as_table_mut() { Some(table) => table, None => { - self.error = Some(ErrorKind::CargoTomlError( - "package should be a table".into(), - )); + // package should be a table + self.error = Some(ErrorKind::ParseError); return; } }; diff --git a/src/lib.rs b/src/lib.rs index d4e31ea88ce..495010a297d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,8 +133,6 @@ pub enum ErrorKind { /// Invalid glob pattern in `ignore` configuration option. #[error("Invalid glob pattern found in ignore list: {0}")] InvalidGlobPattern(ignore::Error), - #[error("Error when formatting Cargo.toml: {0}")] - CargoTomlError(String), } impl ErrorKind { From 1ad83c1d48ac2f5717ea8ae398443510c95734b1 Mon Sep 17 00:00:00 2001 From: xxchan Date: Sun, 20 Nov 2022 22:33:07 +0100 Subject: [PATCH 21/24] move /cargo-toml to /configs/format_cargo_toml --- .../{cargo-toml => configs/format_cargo_toml}/false/Cargo.toml | 0 .../format_cargo_toml}/true/basic/Cargo.toml | 0 .../format_cargo_toml}/true/dotted-key/Cargo.toml | 0 .../format_cargo_toml}/true/virtual-manifest/Cargo.toml | 0 .../{cargo-toml => configs/format_cargo_toml}/false/Cargo.toml | 0 .../format_cargo_toml}/true/basic/Cargo.toml | 0 .../format_cargo_toml}/true/dotted-key/Cargo.toml | 0 .../format_cargo_toml}/true/virtual-manifest/Cargo.toml | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/source/{cargo-toml => configs/format_cargo_toml}/false/Cargo.toml (100%) rename tests/source/{cargo-toml => configs/format_cargo_toml}/true/basic/Cargo.toml (100%) rename tests/source/{cargo-toml => configs/format_cargo_toml}/true/dotted-key/Cargo.toml (100%) rename tests/source/{cargo-toml => configs/format_cargo_toml}/true/virtual-manifest/Cargo.toml (100%) rename tests/target/{cargo-toml => configs/format_cargo_toml}/false/Cargo.toml (100%) rename tests/target/{cargo-toml => configs/format_cargo_toml}/true/basic/Cargo.toml (100%) rename tests/target/{cargo-toml => configs/format_cargo_toml}/true/dotted-key/Cargo.toml (100%) rename tests/target/{cargo-toml => configs/format_cargo_toml}/true/virtual-manifest/Cargo.toml (100%) diff --git a/tests/source/cargo-toml/false/Cargo.toml b/tests/source/configs/format_cargo_toml/false/Cargo.toml similarity index 100% rename from tests/source/cargo-toml/false/Cargo.toml rename to tests/source/configs/format_cargo_toml/false/Cargo.toml diff --git a/tests/source/cargo-toml/true/basic/Cargo.toml b/tests/source/configs/format_cargo_toml/true/basic/Cargo.toml similarity index 100% rename from tests/source/cargo-toml/true/basic/Cargo.toml rename to tests/source/configs/format_cargo_toml/true/basic/Cargo.toml diff --git a/tests/source/cargo-toml/true/dotted-key/Cargo.toml b/tests/source/configs/format_cargo_toml/true/dotted-key/Cargo.toml similarity index 100% rename from tests/source/cargo-toml/true/dotted-key/Cargo.toml rename to tests/source/configs/format_cargo_toml/true/dotted-key/Cargo.toml diff --git a/tests/source/cargo-toml/true/virtual-manifest/Cargo.toml b/tests/source/configs/format_cargo_toml/true/virtual-manifest/Cargo.toml similarity index 100% rename from tests/source/cargo-toml/true/virtual-manifest/Cargo.toml rename to tests/source/configs/format_cargo_toml/true/virtual-manifest/Cargo.toml diff --git a/tests/target/cargo-toml/false/Cargo.toml b/tests/target/configs/format_cargo_toml/false/Cargo.toml similarity index 100% rename from tests/target/cargo-toml/false/Cargo.toml rename to tests/target/configs/format_cargo_toml/false/Cargo.toml diff --git a/tests/target/cargo-toml/true/basic/Cargo.toml b/tests/target/configs/format_cargo_toml/true/basic/Cargo.toml similarity index 100% rename from tests/target/cargo-toml/true/basic/Cargo.toml rename to tests/target/configs/format_cargo_toml/true/basic/Cargo.toml diff --git a/tests/target/cargo-toml/true/dotted-key/Cargo.toml b/tests/target/configs/format_cargo_toml/true/dotted-key/Cargo.toml similarity index 100% rename from tests/target/cargo-toml/true/dotted-key/Cargo.toml rename to tests/target/configs/format_cargo_toml/true/dotted-key/Cargo.toml diff --git a/tests/target/cargo-toml/true/virtual-manifest/Cargo.toml b/tests/target/configs/format_cargo_toml/true/virtual-manifest/Cargo.toml similarity index 100% rename from tests/target/cargo-toml/true/virtual-manifest/Cargo.toml rename to tests/target/configs/format_cargo_toml/true/virtual-manifest/Cargo.toml From 4724d3e7597d7e2bb185e6e00fa30041491bc325 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 8 Aug 2023 03:59:47 -0400 Subject: [PATCH 22/24] Migrate to latest toml_edit crate --- Cargo.lock | 68 ++++-------------------------------- Cargo.toml | 2 +- src/formatting/cargo_toml.rs | 66 ++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db801d8904e..ba9688d7961 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,12 +67,6 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -97,12 +91,6 @@ dependencies = [ "packed_simd_2", ] -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - [[package]] name = "camino" version = "1.0.7" @@ -189,16 +177,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "concolor-override" version = "1.0.0" @@ -343,12 +321,6 @@ dependencies = [ "regex", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.0" @@ -385,16 +357,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.0.0" @@ -402,7 +364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown", ] [[package]] @@ -624,7 +586,7 @@ dependencies = [ "term", "thiserror", "toml", - "toml_edit 0.15.0", + "toml_edit", "tracing", "tracing-subscriber", "unicode-segmentation", @@ -796,16 +758,10 @@ checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.6.3", - "toml_edit 0.19.14", + "toml_datetime", + "toml_edit", ] -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - [[package]] name = "toml_datetime" version = "0.6.3" @@ -815,28 +771,16 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646" -dependencies = [ - "combine", - "indexmap 1.9.3", - "itertools", - "toml_datetime 0.5.1", -] - [[package]] name = "toml_edit" version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 2.0.0", + "indexmap", "serde", "serde_spanned", - "toml_datetime 0.6.3", + "toml_datetime", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 86763479290..eeec16ade31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ thiserror = "1.0.40" toml = "0.7.4" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -toml_edit = "0.15" +toml_edit = "0.19.14" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index e1cb685c13d..8f7407157a1 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -10,7 +10,7 @@ use crate::{Config, ErrorKind}; /// /// [the Style Guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/cargo.md pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result { - let mut doc = content.parse::()?; + let mut doc = content.parse::()?; let rules = [ &mut SortSection { current_position: 0, @@ -31,7 +31,7 @@ pub(crate) fn format_cargo_toml_inner(content: &str, config: &Config) -> Result< for rule in rules.into_iter() { rule.visit_document_mut(&mut doc); } - // Special handling for falliable rules. + // Special handling for fallible rules. let mut rule = SortKey { error: None }; rule.visit_document_mut(&mut doc); if let Some(e) = rule.error { @@ -190,10 +190,10 @@ impl BlankLine { } fn trim_decor_blank_lines(decor: &mut Decor) { - let prefix = decor.prefix().unwrap_or("").to_owned(); - let suffix = decor.suffix().unwrap_or("").to_owned(); - decor.set_prefix(Self::trim_blank_lines(prefix.as_str())); - decor.set_suffix(Self::trim_blank_lines(suffix.as_str())); + let prefix = decor.prefix().cloned().unwrap_or_default(); + let suffix = decor.suffix().cloned().unwrap_or_default(); + decor.set_prefix(Self::trim_blank_lines(prefix.as_str().unwrap_or_default())); + decor.set_suffix(Self::trim_blank_lines(suffix.as_str().unwrap_or_default())); } } @@ -221,8 +221,8 @@ impl VisitMut for BlankLine { }); } else { let decor = table.decor_mut(); - let prefix = decor.prefix().unwrap_or("").to_owned(); - decor.set_prefix("\n".to_owned() + &prefix); + let prefix = decor.prefix().cloned().unwrap_or_default(); + decor.set_prefix(format!("\n{}", prefix.as_str().unwrap_or_default())); } } } @@ -237,7 +237,7 @@ impl KeyValue { impl VisitMut for KeyValue { fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { - let prefix = key.decor().prefix().unwrap_or("").to_owned(); + let prefix = key.decor().prefix().cloned().unwrap_or_default(); if Self::can_be_bare_key(key.get()) { // will remove decors and set the key to the bare key key.fmt(); @@ -246,8 +246,10 @@ impl VisitMut for KeyValue { key.decor_mut().set_suffix(" "); } // start all key names at the start of a line, but preserve comments - key.decor_mut() - .set_prefix(prefix.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')); + if let Some(prefix) = prefix.as_str() { + key.decor_mut() + .set_prefix(prefix.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')); + } if let Some(v) = value.as_value_mut() { v.decor_mut().set_prefix(" "); @@ -405,7 +407,14 @@ impl VisitMut for TrimSpaces { let prefix = format!( "{}{}", if i == 0 { "" } else { "\n" }, - Self::trim_block(decor.prefix().unwrap_or_default()) + Self::trim_block( + decor + .prefix() + .cloned() + .unwrap_or_default() + .as_str() + .unwrap_or_default() + ) ); decor.set_prefix(prefix); }; @@ -420,8 +429,9 @@ impl VisitMut for TrimSpaces { } } - if !node.trailing().trim().is_empty() { - let trailing: String = Self::trim_block(node.trailing()); + let trailing = node.trailing().as_str().unwrap_or_default(); + if !trailing.trim().is_empty() { + let trailing: String = Self::trim_block(trailing); node.set_trailing(&format!("\n{trailing}")); } else { node.set_trailing(""); @@ -431,28 +441,32 @@ impl VisitMut for TrimSpaces { fn visit_table_mut(&mut self, node: &mut Table) { let decor = node.decor_mut(); if let Some(prefix) = decor.prefix() { - decor.set_prefix(format!("\n{}", Self::trim_block(prefix))); - } - if let Some(suffix) = decor.suffix() { - decor.set_suffix(Self::trim_suffix(suffix)); + if let Some(prefix) = prefix.as_str() { + decor.set_prefix(format!("\n{}", Self::trim_block(prefix))); + } } - + trim_suffix(decor); self.visit_table_like_mut(node); } fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { let decor = key.decor_mut(); if let Some(prefix) = decor.prefix() { - decor.set_prefix(format!("{}", Self::trim_block(prefix))); + if let Some(prefix) = prefix.as_str() { + decor.set_prefix(format!("{}", Self::trim_block(prefix))); + } } - if let Some(value) = value.as_value_mut() { - let decor = value.decor_mut(); - if let Some(suffix) = decor.suffix() { - decor.set_suffix(Self::trim_suffix(suffix)); - } + trim_suffix(value.decor_mut()); } - self.visit_item_mut(value); } } + +fn trim_suffix(decor: &mut Decor) { + if let Some(suffix) = decor.suffix() { + if let Some(suffix) = suffix.as_str() { + decor.set_suffix(TrimSpaces::trim_suffix(suffix)); + } + } +} From 09b43a1987d2da068cedca41037adaeccf6633a5 Mon Sep 17 00:00:00 2001 From: xxchan Date: Tue, 24 Oct 2023 23:22:58 +0800 Subject: [PATCH 23/24] update toml_edit to 0.20 --- Cargo.lock | 19 +++++++++++++++---- Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba9688d7961..ca8ed967b97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,7 +586,7 @@ dependencies = [ "term", "thiserror", "toml", - "toml_edit", + "toml_edit 0.20.4", "tracing", "tracing-subscriber", "unicode-segmentation", @@ -759,14 +759,14 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.14", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -784,6 +784,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380f9e8120405471f7c9ad1860a713ef5ece6a670c7eae39225e477340f32fc4" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.37" diff --git a/Cargo.toml b/Cargo.toml index eeec16ade31..712c21b7812 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ thiserror = "1.0.40" toml = "0.7.4" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -toml_edit = "0.19.14" +toml_edit = "0.20.4" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" From c9e5a94a279d8ce821489fd1e3e7b024ba73822e Mon Sep 17 00:00:00 2001 From: xxchan Date: Tue, 24 Oct 2023 23:55:22 +0800 Subject: [PATCH 24/24] improve RawString handling --- src/formatting/cargo_toml.rs | 84 +++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/formatting/cargo_toml.rs b/src/formatting/cargo_toml.rs index 8f7407157a1..f3b0b0b749b 100644 --- a/src/formatting/cargo_toml.rs +++ b/src/formatting/cargo_toml.rs @@ -1,7 +1,8 @@ use itertools::Itertools; use std::cmp::Ordering; use toml_edit::{ - visit_mut::*, Decor, Document, Formatted, Item, KeyMut, Table, TableLike, TomlError, Value, + visit_mut::*, Decor, Document, Formatted, Item, KeyMut, RawString, Table, TableLike, TomlError, + Value, }; use crate::{Config, ErrorKind}; @@ -190,10 +191,12 @@ impl BlankLine { } fn trim_decor_blank_lines(decor: &mut Decor) { - let prefix = decor.prefix().cloned().unwrap_or_default(); - let suffix = decor.suffix().cloned().unwrap_or_default(); - decor.set_prefix(Self::trim_blank_lines(prefix.as_str().unwrap_or_default())); - decor.set_suffix(Self::trim_blank_lines(suffix.as_str().unwrap_or_default())); + if let Some(prefix) = decor.prefix().map(raw_string_as_str) { + decor.set_prefix(Self::trim_blank_lines(prefix)); + } + if let Some(suffix) = decor.suffix().map(raw_string_as_str) { + decor.set_suffix(Self::trim_blank_lines(suffix)); + } } } @@ -221,8 +224,10 @@ impl VisitMut for BlankLine { }); } else { let decor = table.decor_mut(); - let prefix = decor.prefix().cloned().unwrap_or_default(); - decor.set_prefix(format!("\n{}", prefix.as_str().unwrap_or_default())); + decor.set_prefix(format!( + "\n{}", + decor.prefix().map(raw_string_as_str).unwrap_or_default() + )); } } } @@ -237,7 +242,11 @@ impl KeyValue { impl VisitMut for KeyValue { fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { - let prefix = key.decor().prefix().cloned().unwrap_or_default(); + let original_prefix = key + .decor() + .prefix() + .map(raw_string_as_str) + .map(String::from); if Self::can_be_bare_key(key.get()) { // will remove decors and set the key to the bare key key.fmt(); @@ -246,7 +255,7 @@ impl VisitMut for KeyValue { key.decor_mut().set_suffix(" "); } // start all key names at the start of a line, but preserve comments - if let Some(prefix) = prefix.as_str() { + if let Some(prefix) = original_prefix { key.decor_mut() .set_prefix(prefix.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')); } @@ -404,19 +413,14 @@ impl VisitMut for TrimSpaces { self.visit_table_mut(node); let set_prefix = |decor: &mut Decor, i: usize| { - let prefix = format!( - "{}{}", - if i == 0 { "" } else { "\n" }, - Self::trim_block( - decor - .prefix() - .cloned() - .unwrap_or_default() - .as_str() - .unwrap_or_default() - ) - ); - decor.set_prefix(prefix); + if let Some(prefix) = decor.prefix().map(raw_string_as_str) { + let prefix = format!( + "{}{}", + if i == 0 { "" } else { "\n" }, + Self::trim_block(prefix) + ); + decor.set_prefix(prefix); + } }; let table = node.as_table_mut(); for (i, (_, item)) in table.iter_mut().enumerate() { @@ -429,9 +433,9 @@ impl VisitMut for TrimSpaces { } } - let trailing = node.trailing().as_str().unwrap_or_default(); + let trailing = raw_string_as_str(node.trailing()); if !trailing.trim().is_empty() { - let trailing: String = Self::trim_block(trailing); + let trailing = Self::trim_block(trailing); node.set_trailing(&format!("\n{trailing}")); } else { node.set_trailing(""); @@ -440,33 +444,33 @@ impl VisitMut for TrimSpaces { fn visit_table_mut(&mut self, node: &mut Table) { let decor = node.decor_mut(); - if let Some(prefix) = decor.prefix() { - if let Some(prefix) = prefix.as_str() { - decor.set_prefix(format!("\n{}", Self::trim_block(prefix))); - } + if let Some(prefix) = decor.prefix().map(raw_string_as_str) { + decor.set_prefix(format!("\n{}", Self::trim_block(prefix))); + } + if let Some(suffix) = decor.suffix().map(raw_string_as_str) { + decor.set_suffix(Self::trim_suffix(suffix)); } - trim_suffix(decor); self.visit_table_like_mut(node); } fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, value: &mut Item) { let decor = key.decor_mut(); - if let Some(prefix) = decor.prefix() { - if let Some(prefix) = prefix.as_str() { - decor.set_prefix(format!("{}", Self::trim_block(prefix))); - } + if let Some(prefix) = decor.prefix().map(raw_string_as_str) { + decor.set_prefix(format!("{}", Self::trim_block(prefix))); } + if let Some(value) = value.as_value_mut() { - trim_suffix(value.decor_mut()); + let decor = value.decor_mut(); + if let Some(suffix) = decor.suffix().map(raw_string_as_str) { + decor.set_suffix(Self::trim_suffix(suffix)); + } } self.visit_item_mut(value); } } -fn trim_suffix(decor: &mut Decor) { - if let Some(suffix) = decor.suffix() { - if let Some(suffix) = suffix.as_str() { - decor.set_suffix(TrimSpaces::trim_suffix(suffix)); - } - } +/// Note: in `Document::from_str`, the document is despanned, so we can safely unwrap `as_str` +/// when handling `RawString`. +fn raw_string_as_str(raw_string: &RawString) -> &str { + raw_string.as_str().expect("should already be despanded") }