diff --git a/crates/uv-workspace/src/pyproject_mut.rs b/crates/uv-workspace/src/pyproject_mut.rs index 85c36d03d..efdc308c6 100644 --- a/crates/uv-workspace/src/pyproject_mut.rs +++ b/crates/uv-workspace/src/pyproject_mut.rs @@ -1562,29 +1562,29 @@ fn reformat_array_multiline(deps: &mut Array) { let mut indentation_prefix = None; + // Calculate the indentation prefix based on the indentation of the first dependency entry. + if let Some(first_item) = deps.iter().next() { + let decor_prefix = first_item + .decor() + .prefix() + .and_then(|s| s.as_str()) + .and_then(|s| s.lines().last()) + .unwrap_or_default(); + + let decor_prefix = decor_prefix + .split_once('#') + .map(|(s, _)| s) + .unwrap_or(decor_prefix); + + indentation_prefix = (!decor_prefix.is_empty()).then_some(decor_prefix.to_string()); + } + + let indentation_prefix_str = format!("\n{}", indentation_prefix.as_deref().unwrap_or(" ")); + for item in deps.iter_mut() { let decor = item.decor_mut(); let mut prefix = String::new(); - // Calculate the indentation prefix based on the indentation of the first dependency entry. - if indentation_prefix.is_none() { - let decor_prefix = decor - .prefix() - .and_then(|s| s.as_str()) - .and_then(|s| s.lines().last()) - .unwrap_or_default(); - - let decor_prefix = decor_prefix - .split_once('#') - .map(|(s, _)| s) - .unwrap_or(decor_prefix); - - indentation_prefix = (!decor_prefix.is_empty()).then_some(decor_prefix.to_string()); - } - - let indentation_prefix_str = - format!("\n{}", indentation_prefix.as_deref().unwrap_or(" ")); - for comment in find_comments(decor.prefix()).chain(find_comments(decor.suffix())) { match comment.comment_type { CommentType::OwnLine => { diff --git a/crates/uv/tests/it/edit.rs b/crates/uv/tests/it/edit.rs index 92d0d7b6a..1890f2451 100644 --- a/crates/uv/tests/it/edit.rs +++ b/crates/uv/tests/it/edit.rs @@ -13595,3 +13595,58 @@ fn add_path_outside_workspace_no_default() -> Result<()> { Ok(()) } + +/// See: +#[test] +fn add_multiline_indentation() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + + [dependency-groups] + dev = ["ruff", "typing-extensions"] + "#})?; + + uv_snapshot!(context.filters(), context.add().arg("iniconfig").arg("--dev"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 4 packages in [TIME] + Prepared 3 packages in [TIME] + Installed 3 packages in [TIME] + + iniconfig==2.0.0 + + ruff==0.3.4 + + typing-extensions==4.10.0 + "); + + let pyproject_toml = context.read("pyproject.toml"); + + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + pyproject_toml, @r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + + [dependency-groups] + dev = [ + "iniconfig>=2.0.0", + "ruff", + "typing-extensions", + ] + "# + ); + }); + + Ok(()) +}