From 8940cddcf629e54b1be9ffac94e6e07de53caf4f Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 25 Jan 2024 11:20:33 -0500 Subject: [PATCH] fix: handle multi-line strings --- .github/workflows/ci.yml | 14 ++++++++++++++ src/cargo.rs | 2 +- src/configuration/builder.rs | 6 ++---- src/configuration/mod.rs | 1 + src/format_text.rs | 2 +- src/generation/generate.rs | 21 ++++++++++++++------- src/rowan_extensions.rs | 2 +- tests/specs/Issues/Issue0010.txt | 29 +++++++++++++++++++++++++++++ 8 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 tests/specs/Issues/Issue0010.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93c5adb..8c591a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,20 @@ jobs: if: matrix.config.kind == 'test_release' run: cargo test --release + # integration test + - name: Wasm integration test - Setup + if: matrix.config.kind == 'test_release' + run: | + echo '{ "plugins": ["./target/wasm32-unknown-unknown/release/dprint_plugin_toml.wasm"] }' >> dprint.test.json + - name: Wasm integration test - Run + if: matrix.config.kind == 'test_release' + uses: dprint/check@v2.2 + with: + config-path: dprint.test.json + - name: Wasm integration test - Cleanup + if: matrix.config.kind == 'test_release' + run: rm dprint.test.json + - name: Get tag version if: matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/') id: get_tag_version diff --git a/src/cargo.rs b/src/cargo.rs index 2997e7b..1dc5593 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -140,7 +140,7 @@ fn sort_children(children: Vec, cmp: &impl Fn(&SyntaxNode child_groups.into_iter().flatten().collect() } -fn sort_group(child_group: &mut Vec, cmp: &impl Fn(&SyntaxNode, &SyntaxNode) -> Ordering) { +fn sort_group(child_group: &mut [NodeWithLeadingTrivia], cmp: &impl Fn(&SyntaxNode, &SyntaxNode) -> Ordering) { // remove the first item's trivia to get the group trivia let group_trivia: Vec<_> = child_group.first_mut().unwrap().trivia.drain(..).collect(); let previous_first_item_index = child_group.first().unwrap().node.index(); diff --git a/src/configuration/builder.rs b/src/configuration/builder.rs index df2f017..1af6dac 100644 --- a/src/configuration/builder.rs +++ b/src/configuration/builder.rs @@ -16,6 +16,7 @@ use super::*; /// .line_width(80) /// .build(); /// ``` +#[derive(Default)] pub struct ConfigurationBuilder { pub(super) config: ConfigKeyMap, global_config: Option, @@ -24,10 +25,7 @@ pub struct ConfigurationBuilder { impl ConfigurationBuilder { /// Constructs a new configuration builder. pub fn new() -> ConfigurationBuilder { - ConfigurationBuilder { - config: ConfigKeyMap::new(), - global_config: None, - } + ConfigurationBuilder::default() } /// Gets the final configuration that can be used to format a file. diff --git a/src/configuration/mod.rs b/src/configuration/mod.rs index 357e324..be38c0e 100644 --- a/src/configuration/mod.rs +++ b/src/configuration/mod.rs @@ -1,4 +1,5 @@ mod builder; +#[allow(clippy::module_inception)] mod configuration; mod resolve_config; diff --git a/src/format_text.rs b/src/format_text.rs index 4fd7c65..dbd688b 100644 --- a/src/format_text.rs +++ b/src/format_text.rs @@ -40,7 +40,7 @@ fn parse_and_process_node(file_path: &Path, text: &str, config: &Configuration) fn parse_taplo(text: &str) -> Result { let parse_result = taplo::parser::parse(text); - if let Some(err) = parse_result.errors.get(0) { + if let Some(err) = parse_result.errors.first() { bail!( "{}", dprint_core::formatting::utils::string_utils::format_diagnostic(Some((err.range.start().into(), err.range.end().into())), &err.message, text,) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 3704c37..1bb3fb2 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_lifetimes)] + use dprint_core::formatting::conditions::*; use dprint_core::formatting::ir_helpers::SingleLineOptions; use dprint_core::formatting::*; @@ -60,14 +62,20 @@ fn gen_node_with_inner<'a>(node: SyntaxElement, context: &mut Context<'a>, inner }, NodeOrToken::Token(token) => match token.kind() { SyntaxKind::COMMENT => Ok(gen_comment(token, context)), - _ => Ok(ir_helpers::gen_from_string(token.text().trim().into())), + SyntaxKind::MULTI_LINE_STRING | SyntaxKind::MULTI_LINE_STRING_LITERAL => { + let mut items = PrintItems::new(); + items.push_str(""); + items.extend(ir_helpers::gen_from_raw_string(token.text().trim())); + Ok(items) + } + _ => Ok(ir_helpers::gen_from_string(token.text().trim())), }, }; items.extend(inner_parse( match result { Ok(items) => items, - Err(()) => ir_helpers::gen_from_raw_string_trim_line_ends(node.text().trim().into()), + Err(()) => ir_helpers::gen_from_raw_string_trim_line_ends(node.text().trim()), }, context, )); @@ -182,7 +190,7 @@ fn gen_inline_table<'a>(node: SyntaxNode, context: &mut Context<'a>) -> PrintIte // the comment seems to be stored as the last child of an inline table, so check for it here if let Some(NodeOrToken::Token(token)) = node.children_with_tokens().last() { if token.kind() == SyntaxKind::COMMENT { - items.extend(gen_comment(token.into(), context)); + items.extend(gen_comment(token, context)); } } @@ -348,7 +356,7 @@ fn gen_comma_separated_value<'a>(value: SyntaxElement, generated_comma: PrintIte let generated_comma = generated_comma.into_rc_path(); items.extend(gen_node_with_inner(value, context, move |mut items, _| { // this Rc clone is necessary because we can't move the captured generated_comma out of this closure - items.push_optional_path(generated_comma.clone()); + items.push_optional_path(generated_comma); items })); @@ -386,7 +394,7 @@ fn gen_comment<'a>(comment: SyntaxToken, context: &mut Context<'a>) -> PrintItem let mut text = "#".repeat(info.leading_hashes_count); if !after_hash_text.is_empty() { if !info.has_leading_whitespace { - text.push_str(" "); + text.push(' '); } text.push_str(after_hash_text); } @@ -405,10 +413,9 @@ struct CommentTextInfo { } fn get_comment_text_info(text: &str) -> CommentTextInfo { - let mut chars = text.chars(); let mut leading_hashes_count = 0; let mut has_leading_whitespace = false; - while let Some(c) = chars.next() { + for c in text.chars() { match c { '#' => leading_hashes_count += 1, ' ' | '\t' => { diff --git a/src/rowan_extensions.rs b/src/rowan_extensions.rs index 511467b..eff080b 100644 --- a/src/rowan_extensions.rs +++ b/src/rowan_extensions.rs @@ -23,7 +23,7 @@ impl SyntaxElementExtensions for SyntaxElement { fn start_including_leading_comments(&self) -> usize { let result = self.get_comments_on_previous_lines(); - if let Some(comment) = result.get(0) { + if let Some(comment) = result.first() { comment.text_range().start().into() } else { self.text_range().start().into() diff --git a/tests/specs/Issues/Issue0010.txt b/tests/specs/Issues/Issue0010.txt new file mode 100644 index 0000000..a49c37e --- /dev/null +++ b/tests/specs/Issues/Issue0010.txt @@ -0,0 +1,29 @@ +== should format multi-line strings (only) == +strings = [ + """ + This is + a + multi-line + string + """, + '''This is + a multi-line literal string + + + ''', +] + +[expect] +strings = [ + """ + This is + a + multi-line + string + """, + '''This is + a multi-line literal string + + + ''', +]