Repository: nix-community/nixpkgs-fmt (rust)

Issue:
sample: `builtins.fold' (` causes funky indentation for following arguments
## Input
```nix
    (
      builtins.foldl' (
        acc: v: let
          isOperator = builtins.typeOf v == "list";
          operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
        in
          if isOperator then (acc // { inherit operator; }) else {
            inherit operator;
            state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
          }
      )
        {
          operator = ",";
          state = true;
        }
        tokens
    ).state;
```

## Output
```nix
(
  builtins.foldl' (
    acc: v: let
      isOperator = builtins.typeOf v == "list";
      operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
    in
      if isOperator then (acc // { inherit operator; }) else {
        inherit operator;
        state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
      }
  )
    {
      operator = ",";
      state = true;
    }
    tokens
).state;

```

## Desired output

```nix
(
  builtins.foldl'
    (
      acc: v: let
        isOperator = builtins.typeOf v == "list";
        operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
      in
        if isOperator then (acc // { inherit operator; }) else {
          inherit operator;
          state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
        }
    )
    {
      operator = ",";
      state = true;
    }
    tokens
).state;
```


Pull request description:
Fix #161: Align the function apply with the attribute set
This PR only force linebreak if after the apply function exists parenthesis. The curly bracket will remain inline.

Patch:
diff --git a/src/rules.rs b/src/rules.rs
index 8fc56c9..e409ca5 100644
--- a/src/rules.rs
+++ b/src/rules.rs
@@ -99,6 +99,7 @@ pub(crate) fn spacing() -> SpacingDsl {
 
         .test("f  x", "f x")
         .inside(NODE_APPLY).between(VALUES, VALUES).single_space_or_optional_newline()
+        .inside(NODE_APPLY).after(NODE_SELECT).when(next_sibling_is_paren).single_space_or_newline()
 
         .test("if  cond  then  tru  else  fls", "if cond then tru else fls")
         .inside(NODE_IF_ELSE).after(T![if]).single_space_or_optional_newline()
@@ -176,6 +177,12 @@ fn next_sibling_has_newline(element: &SyntaxElement) -> bool {
         .unwrap_or(false)
 }
 
+fn next_sibling_is_paren(element: &SyntaxElement) -> bool {
+    next_non_whitespace_sibling(element)
+        .and_then(|e| e.into_node().map(|t| t.kind() == NODE_PAREN))
+        .unwrap_or(false)
+}
+
 fn next_sibling_is_multiline_lambda_pattern(element: &SyntaxElement) -> bool {
     fn find(element: &SyntaxElement) -> Option<bool> {
         let lambda = next_non_whitespace_sibling(element)?.into_node().and_then(Lambda::cast)?;


Test patch:
diff --git a/test_data/issue-161.bad.nix b/test_data/issue-161.bad.nix
new file mode 100644
index 0000000..afed9be
--- /dev/null
+++ b/test_data/issue-161.bad.nix
@@ -0,0 +1,17 @@
+(
+  builtins.foldl' (
+    acc: v: let
+      isOperator = builtins.typeOf v == "list";
+      operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
+    in
+      if isOperator then (acc // { inherit operator; }) else {
+        inherit operator;
+        state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
+      }
+  )
+    {
+      operator = ",";
+      state = true;
+    }
+    tokens
+).state
diff --git a/test_data/issue-161.good.nix b/test_data/issue-161.good.nix
new file mode 100644
index 0000000..6b27f9d
--- /dev/null
+++ b/test_data/issue-161.good.nix
@@ -0,0 +1,19 @@
+(
+  builtins.foldl'
+    (
+      acc: v:
+        let
+          isOperator = builtins.typeOf v == "list";
+          operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
+        in
+          if isOperator then (acc // { inherit operator; }) else {
+            inherit operator;
+            state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
+          }
+    )
+    {
+      operator = ",";
+      state = true;
+    }
+    tokens
+).state