From 4347fa9b56c68054481428f73cf1f3a3840ea951 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 20 Sep 2024 17:02:04 +0200 Subject: [PATCH] After the stream --- src/Fantomas.Core.Tests/OperatorTests.fs | 214 ++++++++++ src/Fantomas.Core/ASTTransformer.fs | 7 +- src/Fantomas.Core/CodePrinter.fs | 510 +++++++++++++---------- src/Fantomas.Core/Selection.fs | 12 +- src/Fantomas.Core/SyntaxOak.fs | 16 +- src/Fantomas.Core/Trivia.fs | 4 +- 6 files changed, 520 insertions(+), 243 deletions(-) diff --git a/src/Fantomas.Core.Tests/OperatorTests.fs b/src/Fantomas.Core.Tests/OperatorTests.fs index 75d2c59ad7..fc8ce1ff9c 100644 --- a/src/Fantomas.Core.Tests/OperatorTests.fs +++ b/src/Fantomas.Core.Tests/OperatorTests.fs @@ -1537,3 +1537,217 @@ let f a b = a + b let foo () = f %%"17" %%"42" """ + +(* + + ░▒▓██████▓▒░░▒▓██████████████▓▒░░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓███████▓▒░ ░▒▓██████▓▒░ ░▒▓████████▓▒░▒▓███████▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░░▒▓███████▓▒░ +░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ +░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ +░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓██████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░ ░▒▓██████▓▒░ ░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░▒▓███████▓▒░░▒▓███████▓▒░ +░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ +░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ +░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓ + +*) + +(* +Before we start: + +- Announcement: https://github.com/fsprojects/fantomas/issues/3112 +- v7: https://github.com/fsprojects/fantomas/pull/3123 + +*) + +// Override config to similar multiline behavior +let config = { config with MaxLineLength = 10 } + +// Skip setting https://fsprojects.github.io/fantomas/docs/end-users/Configuration.html#fsharp_max_infix_operator_expression + +[] +let ``simple single line sample`` () = + formatSourceString + """ +1 + 2 +""" + config + |> prepend newline + |> should + equal + """ +1 + 2 +""" + +// Or should the `+` be on the line below? +// Style guide to the rescue? https://learn.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-arithmetic-and-binary-expressions +// Existing behavior: http://localhost:9060/fantomas-tools/#/fantomas/main?data=N4KABGBEDGD2AmBTSAuKBDTXNgNQB0AnfAOwCMLKqzIAacKAZ0QBcWBLEgc0dTAG0GEUBFFQAJCwCeAB2RpInFnSGjI4gG7oANgFd5A1WIAM9MWMgBJEkhIsAyuwBeyM%2BYgAWI2AC6qgL5uwt7q0nJ8inYq7upaegaC7hAAjEHmkACy6AAeADKciLmI3CwAFtFJycbefmKBqiLpkrIGkMXwAPIAZvkkiPbS2q4hmjr6fIlJAExpFgCiNt29w0lQ0ITaXZA1AWmNFs3hCmSwsNoVB3HjaJPuAMyzatbMhCwAYpw6AHKIAO7aBQu5hYhH0OzqexGYVaJzOQIgsTGCW8nkeCPsMnQ0EQACFEF1YIREAAFdCEdAAW1YiEI8NEILB7lqonqYn2akOMNO50eiPiExRYAArGioBisbj8YTCrBfjToOhmNYNLAFRxYCQ6RAGYhwSzITFORFYTyRldkasAGyiyDi7F4glEgCqMjkhAVSpIKrV7A1WrAXR0zD1EFZonZCKNx25dL510MqwA7Da7ZLHYgAMLaRWMDMaxgM6AsQn%2BwPaYNM3YNKEtY0x3mjfk3QUADhTmPtUqJGUQFLINNLQd1lYh1cN0LrcIb5oFqwAnO2JQ7pXntH7RWWK%2BZmaGDU0J9Gp2akbPKqZBbaO4gAIJdFg0vMUinof06kNgMPBce1w%2Bmw0z5tVmSVIL1TZciXsXt2DgNdNQ3Id30-MAIwkA8oBNWNG3jW5zGSGZQKvW970ISCKWgs510FN8R31Md9x-dD62PJsE0qB4CIla9CFgXQbAAEUQAEyOI19QWHbcqzZGsjigJRMIA1j3GSDwbSybJLC6AAVUpinsUpCRYAB1dh4DKf1qho3c6IONDImUacT0AyoRQvNSNO04o5nLfp9NeYzTPKUVLQsiTRyk78ZLs%2BTHMU3DrVcnJrC6dhsg6N10GLQg5myGQiUYRhfTg1sQrEHcPz3GyGKihyWJwsRkmTBLsgAJUQOBCHgfyzNFDwStEMqkJQ0IqrkmrsMFZI2ya1r2vgL5dD7Glukse8KV4UVkkQiqOVsildG0DgAT6N5CWfNgaU02sxotSoFwvGbCXgDJ9sOgoTsIM6RJtaBSjJLFiIAfV%2BEyzK26ydpGqJrtPdwpnPVZMhyLjySkDpCHyAsusC4qwfC%2BjItG5jxtWKYQIRtTkfQVH0fYAt5sWwhltW9aJtx8NpNaPaDvYI7EHez6Lquombth-CEcp6mMZYZ7ud5-mMq%2Bi8fr%2BosaSBkHyjZr98daQn-xiurRCmdjyZyAA1JEcU4eBOC4LH-RbPqIAG7bI1svWmgUw2ICmFSmreXii0Kq2bFt%2B2eqd3xJPZiLdah4WYfMKYXNN7I%2BNgFgAHFWGy3LEHywrw5xyzyvBt2qow6GnNh%2BKEZ%2Bf4CjxFg5WKS65AE5KSHYdUSGvGwewZlnVmo0LaLxyrIsrhPq6TxrxYBLgSADkgg41RxF4y3QiU02BrFsFgMsKwdvK15COcnP9PYNwUpim%2BfiJIQ%2BNBlbgB-7QgO84bvCqHpJN3E0q0dtYTy5EefWtUb53XJi9dgyxciUjIPAdAWZYAFW4PXXmx8tyALCjHHWF9ooQNWHceGSRIC5xpOwKkdgdAAGlECIBkHvYoLBrA4nJCvbGqx-6nyGlGRiYCr5EKSHcMmZCcTZhIAAa2WIwLiPEbA-ALIgJ6MDea5zygVfMolGSjysuPCGk8mLgOJiIsW4iyTgUQHxWm6wqGfHvPAJ0XcNQCWgNmckPcsEAP6kAs%2BscIhc1en0dhWIpGsAGFIIYhDTH3BNmQmWwTcTkmgOEhwgwVhkPWJSOQ8Btgl0GufBQHtLjX2IX7BG9DGFqXpu-boEj0DSNkf6KokcXZl1QhXYxQjYnmDuCnMhGDG5dkQIknmBRHwyF0AfHuGj85aKKsPMSvCikCMvqU4R9xa5kIoYQKhLCdBeTIowLhf8EIFIYD4NwihGBvAKnwHh-ggA + +[] +let ``multiline example`` () = + formatSourceString + """ +aaaaaaaa + bbbbbbbbbbb +""" + config + |> prepend newline + |> should + equal + """ +aaaaaaaa + +bbbbbbbbbbb +""" + +// What about non-arithmetic operators +// https://github.com/fsharp/fslang-design/issues/687 + +[] +let ``going fishing`` () = + formatSourceString + """ +aaaaaaaaa >=> bbbbbbbbbbbb +""" + config + |> prepend newline + |> should + equal + """ +aaaaaaaaa +>=> bbbbbbbbbbbb +""" + +// Some operators can never be break +// Example: http://localhost:9060/fantomas-tools/#/ast?data=N4KABGBEAmCmBmBLAdrAzpAXFSAacUiaAYmolmPAIYA2as%2BEkAxgPZwWRXc-dgC8AHQBOg5ACNJU6eLwFIsAB4AHKsmgUALsICusEAF8gA + +[] +let ``never break`` () = + formatSourceString + """ +aaaaaaa = bbbbbbb +""" + config + |> prepend newline + |> should + equal + """ +aaaaaaa = bbbbbbb +""" + +// But what is the right hand side is multiline? + +[] +let ``equals with multiline rhs`` () = + formatSourceString + """ +x.FooBar = Some y +""" + { config with MaxLineLength = 5 } + |> prepend newline + |> should + equal + """ +x.FooBar = + Some + y +""" + +// When having multiple operators, you sometimes want group them + +[] +let ``multiple pipes`` () = + formatSourceString + """ +aa |> bb |> cccccccccccccc +""" + config + |> prepend newline + |> should + equal + """ +aa +|> bb +|> cccccccccccccc +""" + +// Keeping indentation flow is hard +// Related: https://github.com/fsprojects/fantomas/issues/3117 + +[] +let ``indentation flow`` () = + formatSourceString + """ +let v = + expr1 + +> if a then b else c +""" + config + |> prepend newline + |> should + equal + """ +let v = + expr1 + +> if + a + then + b + else + c +""" + +// arithmetic operator cannot always be on the right side + +[] +let ``patterns matching and lambda are though`` () = + formatSourceString + """ + match [] with | [] -> 0 | _ -> 42 + + + 2 +""" + config + |> prepend newline + |> should + equal + """ +match + [] +with +| [] -> 0 +| _ -> 42 ++ 2 +""" + +[] +let ``parens to the rescue`` () = + formatSourceString + """ +(match [] with | [] -> 0 | _ -> 42) + 2 +""" + config + |> prepend newline + |> should + equal + """ +(match + [] + with + | [] -> 0 + | _ -> 42) + +2 +""" + +// How about arithmetic operators until the line is full? + +[] +let ``place expressions until the line is full`` () = + formatSourceString + """ +a + b + c + d +""" + config + |> prepend newline + |> should + equal + """ +a + b + c + +d +""" diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs index 5544c70226..6f1d53369a 100644 --- a/src/Fantomas.Core/ASTTransformer.fs +++ b/src/Fantomas.Core/ASTTransformer.fs @@ -1,5 +1,7 @@ module internal rec Fantomas.Core.ASTTransformer +#nowarn "FS1182" + open System.Collections.Generic open System.Text.RegularExpressions open Fantomas.FCS.Text @@ -442,6 +444,7 @@ let (|IndexWithoutDot|_|) expr = Some(identifierExpr, indexExpr) | _ -> None +// :: a :: let (|MultipleConsInfixApps|_|) expr = let rec visit expr (headAndLastOperator: (SynExpr * SingleTextNode) option) (xs: Queue) = match expr with @@ -1223,8 +1226,8 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr = ExprPrefixAppNode(stn operatorName ident.idRange, mkExpr creationAide e2, exprRange) |> Expr.PrefixApp - | NewlineInfixApps(head, xs) - | MultipleConsInfixApps(head, xs) + // | NewlineInfixApps(head, xs) + // | MultipleConsInfixApps(head, xs) | SameInfixApps(head, xs) -> let rest = xs |> List.map (fun (operator, e) -> operator, mkExpr creationAide e) diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index 357eaf63af..06ef3a694e 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -5,8 +5,9 @@ open Fantomas.Core.Context open Fantomas.Core.SyntaxOak open Microsoft.FSharp.Core.CompilerServices +let arithmeticOperators = set [ "+" ] let noBreakInfixOps = set [| "="; ">"; "<"; "%" |] -let newLineInfixOps = set [ "|>"; "||>"; "|||>"; ">>"; ">>=" ] +// let newLineInfixOps = set [ "|>"; "||>"; "|||>"; ">>"; ">>=" ] let rec (|UppercaseType|LowercaseType|) (t: Type) : Choice = let upperOrLower (v: string) = @@ -781,81 +782,81 @@ let genExpr (e: Expr) = | _ -> fallback | _ -> fallback |> genNode node - | Expr.SameInfixApps node -> - let headIsSynExprLambdaOrIfThenElse = isLambdaOrIfThenElse node.LeadingExpr - - let shortExpr = - onlyIf headIsSynExprLambdaOrIfThenElse sepOpenT - +> genExpr node.LeadingExpr - +> onlyIf headIsSynExprLambdaOrIfThenElse sepCloseT - +> sepSpace - +> col sepSpace node.SubsequentExpressions (fun (operator, rhs) -> - genSingleTextNode operator - +> sepSpace - +> onlyIf (isLambdaOrIfThenElse rhs) sepOpenT - +> genExpr rhs - +> onlyIf (isLambdaOrIfThenElse rhs) sepCloseT) - - let multilineExpr = - match node.SubsequentExpressions with - | [] -> genExpr node.LeadingExpr - | (operator, e2) :: es -> - let m = - Fantomas.FCS.Text.Range.unionRanges (Expr.Node node.LeadingExpr).Range (Expr.Node e2).Range - - genMultilineInfixExpr (ExprInfixAppNode(node.LeadingExpr, operator, e2, m)) - +> sepNln - +> col sepNln es (fun (operator, e) -> - genSingleTextNode operator - +> sepNlnWhenWriteBeforeNewlineNotEmptyOr sepSpace - +> (fun ctx -> - match e with - | Expr.Lambda _ when - newLineInfixOps.Contains operator.Text - && ctx.Config.IndentSize <= operator.Text.Length - -> - // Special measure to account for https://github.com/fsprojects/fantomas/issues/870 - (indent +> genExprInMultilineInfixExpr e +> unindent) ctx - | _ -> genExprInMultilineInfixExpr e ctx)) - - fun ctx -> - genNode - node - (atCurrentColumn (isShortExpression ctx.Config.MaxInfixOperatorExpression shortExpr multilineExpr)) - ctx - - | Expr.InfixApp node -> - let genOnelinerInfixExpr (node: ExprInfixAppNode) = - let genExpr e = - match e with - | Expr.Record _ - | Expr.AnonStructRecord _ -> atCurrentColumnIndent (genExpr e) - | _ -> genExpr e - - genExpr node.LeftHandSide - +> sepSpace - +> genSingleTextNode node.Operator - +> sepNlnWhenWriteBeforeNewlineNotEmpty - +> sepSpace - +> genExpr node.RightHandSide - - if - isLambdaOrIfThenElse node.LeftHandSide - && newLineInfixOps.Contains node.Operator.Text - then - genNode node (genMultilineInfixExpr node) - else - fun ctx -> - genNode - node - (isShortExpression - ctx.Config.MaxInfixOperatorExpression - (genOnelinerInfixExpr node) - (ifElse - (noBreakInfixOps.Contains(node.Operator.Text)) - (genOnelinerInfixExpr node) - (genMultilineInfixExpr node))) - ctx + // | Expr.SameInfixApps node -> + // let headIsSynExprLambdaOrIfThenElse = isLambdaOrIfThenElse node.LeadingExpr + // + // let shortExpr = + // onlyIf headIsSynExprLambdaOrIfThenElse sepOpenT + // +> genExpr node.LeadingExpr + // +> onlyIf headIsSynExprLambdaOrIfThenElse sepCloseT + // +> sepSpace + // +> col sepSpace node.SubsequentExpressions (fun (operator, rhs) -> + // genSingleTextNode operator + // +> sepSpace + // +> onlyIf (isLambdaOrIfThenElse rhs) sepOpenT + // +> genExpr rhs + // +> onlyIf (isLambdaOrIfThenElse rhs) sepCloseT) + // + // let multilineExpr = + // match node.SubsequentExpressions with + // | [] -> genExpr node.LeadingExpr + // | (operator, e2) :: es -> + // let m = + // Fantomas.FCS.Text.Range.unionRanges (Expr.Node node.LeadingExpr).Range (Expr.Node e2).Range + // + // genMultilineInfixExpr (ExprInfixAppNode(node.LeadingExpr, operator, e2, m)) + // +> sepNln + // +> col sepNln es (fun (operator, e) -> + // genSingleTextNode operator + // +> sepNlnWhenWriteBeforeNewlineNotEmptyOr sepSpace + // +> (fun ctx -> + // match e with + // | Expr.Lambda _ when + // newLineInfixOps.Contains operator.Text + // && ctx.Config.IndentSize <= operator.Text.Length + // -> + // // Special measure to account for https://github.com/fsprojects/fantomas/issues/870 + // (indent +> genExprInMultilineInfixExpr e +> unindent) ctx + // | _ -> genExprInMultilineInfixExpr e ctx)) + // + // fun ctx -> + // genNode + // node + // (atCurrentColumn (isShortExpression ctx.Config.MaxInfixOperatorExpression shortExpr multilineExpr)) + // ctx + // + // | Expr.InfixApp node -> + // let genOnelinerInfixExpr (node: ExprInfixAppNode) = + // let genExpr e = + // match e with + // | Expr.Record _ + // | Expr.AnonStructRecord _ -> atCurrentColumnIndent (genExpr e) + // | _ -> genExpr e + // + // genExpr node.LeftHandSide + // +> sepSpace + // +> genSingleTextNode node.Operator + // +> sepNlnWhenWriteBeforeNewlineNotEmpty + // +> sepSpace + // +> genExpr node.RightHandSide + // + // if + // isLambdaOrIfThenElse node.LeftHandSide + // && newLineInfixOps.Contains node.Operator.Text + // then + // genNode node (genMultilineInfixExpr node) + // else + // fun ctx -> + // genNode + // node + // (isShortExpression + // ctx.Config.MaxInfixOperatorExpression + // (genOnelinerInfixExpr node) + // (ifElse + // (noBreakInfixOps.Contains(node.Operator.Text)) + // (genOnelinerInfixExpr node) + // (genMultilineInfixExpr node))) + // ctx | Expr.IndexWithoutDot node -> let genIdentifierExpr = @@ -1324,7 +1325,7 @@ let genExpr (e: Expr) = +> genExpr node.ElseExpr) long ctx) - |> atCurrentColumnIndent + // |> atCurrentColumnIndent |> genNode node | Expr.IfThenElif node -> // multiple branches but no else expr @@ -1598,6 +1599,65 @@ let genExpr (e: Expr) = genSingleTextNode node.Then +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr node.Expr) |> genNode node + | Expr.SameInfixApps node -> + genExpr node.LeadingExpr + +> sepSpace + +> colEx + (fun (operator, expr) ctx -> + ignore ((operator: SingleTextNode), expr) + sepSpace ctx + + // if arithmeticOperators.Contains(operator.Text) + // && futureNlnCheck (genSingleTextNode operator +> genExpr expr) ctx then + // sepNln ctx + // else + // sepSpace ctx + ) + node.SubsequentExpressions + (fun (operator, expr) -> + genSingleTextNode operator + +> expressionFitsOnRestOfLine (sepSpace +> genExpr expr) (sepNln +> genExpr expr)) + + | Expr.InfixApp node -> + let short = + genExpr node.LeftHandSide + +> sepSpace + +> genSingleTextNode node.Operator + +> sepSpace + +> genExpr node.RightHandSide + + let long ctx = + if + arithmeticOperators.Contains(node.Operator.Text) + && not ( + match node.LeftHandSide with + | Expr.Match _ -> futureNlnCheck (genExpr node.LeftHandSide) ctx + | _ -> false + ) + then + (genExpr node.LeftHandSide + +> sepSpace + +> genSingleTextNode node.Operator + +> sepNln + +> genExpr node.RightHandSide) + ctx + elif noBreakInfixOps.Contains(node.Operator.Text) then + (genExpr node.LeftHandSide + +> sepSpace + +> genSingleTextNode node.Operator + +> indentSepNlnUnindent (genExpr node.RightHandSide)) + ctx + else + (genExpr node.LeftHandSide + +> sepNln + +> indent + +> genSingleTextNode node.Operator + +> sepSpace + +> genExpr node.RightHandSide + +> unindent) + ctx + + expressionFitsOnRestOfLine short long let genQuoteExpr (node: ExprQuoteNode) = genSingleTextNode node.OpenToken @@ -1848,7 +1908,7 @@ let genMultilineFunctionApplicationArguments (argExpr: Expr) = let genExpr e = match e with - | Expr.InfixApp infixNode when (infixNode.Operator.Text = "=") -> genNamedArgumentExpr infixNode + // | Expr.InfixApp infixNode when (infixNode.Operator.Text = "=") -> genNamedArgumentExpr infixNode | _ -> genExpr e match argExpr with @@ -1867,24 +1927,24 @@ let genTupleExpr (node: ExprTupleNode) = // see 2819 let wrapInfixAppRhsInParenIfNeeded expr = match expr with - | Expr.InfixApp exprInfixAppNode -> - match exprInfixAppNode.RightHandSide with - | IsLambdaOrIfThenElse e -> - let parenNode = - mkExprParenNode - (SingleTextNode("(", Fantomas.FCS.Text.Range.Zero)) - e - (SingleTextNode(")", Fantomas.FCS.Text.Range.Zero)) - Fantomas.FCS.Text.Range.Zero - - ExprInfixAppNode( - exprInfixAppNode.LeftHandSide, - exprInfixAppNode.Operator, - parenNode, - Fantomas.FCS.Text.range.Zero - ) - |> Expr.InfixApp - | _ -> expr + // | Expr.InfixApp exprInfixAppNode -> + // match exprInfixAppNode.RightHandSide with + // | IsLambdaOrIfThenElse e -> + // let parenNode = + // mkExprParenNode + // (SingleTextNode("(", Fantomas.FCS.Text.Range.Zero)) + // e + // (SingleTextNode(")", Fantomas.FCS.Text.Range.Zero)) + // Fantomas.FCS.Text.Range.Zero + // + // ExprInfixAppNode( + // exprInfixAppNode.LeftHandSide, + // exprInfixAppNode.Operator, + // parenNode, + // Fantomas.FCS.Text.range.Zero + // ) + // |> Expr.InfixApp + // | _ -> expr | _ -> expr let shortExpression = @@ -1914,15 +1974,15 @@ let genTupleMultiline (node: ExprTupleNode) = match e with | Expr.Match _ | Expr.Lambda _ -> true - | Expr.InfixApp node -> - match node.RightHandSide with - | Expr.Match _ - | Expr.Lambda _ -> true - | _ -> false - | Expr.SameInfixApps node -> - match List.last node.SubsequentExpressions with - | _, Expr.Lambda _ -> true - | _ -> false + // | Expr.InfixApp node -> + // match node.RightHandSide with + // | Expr.Match _ + // | Expr.Lambda _ -> true + // | _ -> false + // | Expr.SameInfixApps node -> + // match List.last node.SubsequentExpressions with + // | _, Expr.Lambda _ -> true + // | _ -> false | _ -> false | _ -> false) @@ -1933,7 +1993,7 @@ let genTupleMultiline (node: ExprTupleNode) = | Choice1Of2 e -> match e with | IsIfThenElse _ when (idx < lastIndex) -> autoParenthesisIfExpressionExceedsPageWidth (genExpr e) - | Expr.InfixApp node when (node.Operator.Text = "=") -> genNamedArgumentExpr node + // | Expr.InfixApp node when (node.Operator.Text = "=") -> genNamedArgumentExpr node | _ -> genExpr e | Choice2Of2 comma -> if containsLambdaOrMatchExpr then @@ -1943,21 +2003,21 @@ let genTupleMultiline (node: ExprTupleNode) = coli sepNone node.Items genItem -let genNamedArgumentExpr (node: ExprInfixAppNode) = - let short = - genExpr node.LeftHandSide - +> sepSpace - +> genSingleTextNode node.Operator - +> sepSpace - +> genExpr node.RightHandSide - - let long = - genExpr node.LeftHandSide - +> sepSpace - +> genSingleTextNode node.Operator - +> indentSepNlnUnindentUnlessStroustrup (fun e -> sepSpace +> genExpr e) node.RightHandSide - - expressionFitsOnRestOfLine short long |> genNode node +// let genNamedArgumentExpr (node: ExprInfixAppNode) = +// let short = +// genExpr node.LeftHandSide +// +> sepSpace +// +> genSingleTextNode node.Operator +// +> sepSpace +// +> genExpr node.RightHandSide +// +// let long = +// genExpr node.LeftHandSide +// +> sepSpace +// +> genSingleTextNode node.Operator +// +> indentSepNlnUnindentUnlessStroustrup (fun e -> sepSpace +> genExpr e) node.RightHandSide +// +// expressionFitsOnRestOfLine short long |> genNode node let genLambdaAux (includeClosingParen: bool) (node: ExprLambdaNode) = let genPats = @@ -2176,110 +2236,110 @@ let genControlExpressionStartCore +> leaveNode endKeyword // Caller of this function is responsible for genNode! -let genMultilineInfixExpr (node: ExprInfixAppNode) = - let genLhs (ctx: Context) = - match node.LeftHandSide with - | IsIfThenElse _ when (ctx.Config.IndentSize - 1 <= node.Operator.Text.Length) -> - autoParenthesisIfExpressionExceedsPageWidth (genExpr node.LeftHandSide) ctx - | Expr.Match _ when (ctx.Config.IndentSize - 1 <= node.Operator.Text.Length) -> - let ctxAfterMatch = genExpr node.LeftHandSide ctx - - let lastClauseIsSingleLine = - Queue.rev ctxAfterMatch.WriterEvents - |> Seq.skipWhile (fun e -> - match e with - | RestoreIndent _ - | RestoreAtColumn _ -> true - | _ -> false) - // In case the last clause was multiline an UnIndent event should follow - |> Seq.tryHead - |> fun e -> - match e with - | Some(UnIndentBy _) -> false - | _ -> true - - if lastClauseIsSingleLine then - ctxAfterMatch - else - autoParenthesisIfExpressionExceedsPageWidth (genExpr node.LeftHandSide) ctx - | lhsExpr -> genExpr lhsExpr ctx - - atCurrentColumn ( - genLhs - +> sepNln - +> genSingleTextNode node.Operator - +> sepNlnWhenWriteBeforeNewlineNotEmpty - +> sepSpace - +> genExprInMultilineInfixExpr node.RightHandSide - ) - -let genExprInMultilineInfixExpr (e: Expr) = - match e with - | Expr.CompExprBody node -> - let areLetOrUseStatementsEndingWithOtherStatement = - node.Statements - |> List.mapWithLast - (function - | ComputationExpressionStatement.LetOrUseStatement _ -> true - | _ -> false) - (function - | ComputationExpressionStatement.OtherStatement _ -> true - | _ -> false) - |> List.reduce (&&) - - if not areLetOrUseStatementsEndingWithOtherStatement then - genExpr e - else - colWithNlnWhenMappedNodeIsMultiline - true - ComputationExpressionStatement.Node - (fun ces -> - match ces with - | ComputationExpressionStatement.LetOrUseStatement letOrUseNode -> - let genIn = - match letOrUseNode.In with - | None -> !- "in" - | Some inNode -> genSingleTextNode inNode - - genBinding letOrUseNode.Binding +> sepSpace +> genIn +> sepSpace - |> genNode letOrUseNode - | ComputationExpressionStatement.OtherStatement otherNode -> genExpr otherNode - | _ -> failwith "unexpected ComputationExpressionStatement") - node.Statements - |> atCurrentColumn - |> genNode node - | Expr.Paren parenNode -> - match parenNode.Expr with - | Expr.Match _ as mex -> - fun ctx -> - if ctx.Config.MultiLineLambdaClosingNewline then - genNode - parenNode - (genSingleTextNode parenNode.OpeningParen - +> indentSepNlnUnindent (genExpr mex) - +> sepNln - +> genSingleTextNode parenNode.ClosingParen) - ctx - else - genNode - parenNode - (genSingleTextNode parenNode.OpeningParen - +> atCurrentColumnIndent (genExpr mex) - +> genSingleTextNode parenNode.ClosingParen) - ctx - | Expr.InfixApp infixNode -> - match infixNode.LeftHandSide with - | Expr.Chain _ -> atCurrentColumnIndent (genExpr e) - | _ -> genExpr e - | Expr.Chain _ - | Expr.Record _ -> atCurrentColumnIndent (genExpr e) - | _ -> genExpr e - | Expr.MatchLambda matchLambdaNode -> - genSingleTextNode matchLambdaNode.Function - +> indentSepNlnUnindent (genClauses matchLambdaNode.Clauses) - |> genNode matchLambdaNode - | Expr.Record _ -> atCurrentColumnIndent (genExpr e) - | _ -> genExpr e +// let genMultilineInfixExpr (node: ExprInfixAppNode) = +// let genLhs (ctx: Context) = +// match node.LeftHandSide with +// | IsIfThenElse _ when (ctx.Config.IndentSize - 1 <= node.Operator.Text.Length) -> +// autoParenthesisIfExpressionExceedsPageWidth (genExpr node.LeftHandSide) ctx +// | Expr.Match _ when (ctx.Config.IndentSize - 1 <= node.Operator.Text.Length) -> +// let ctxAfterMatch = genExpr node.LeftHandSide ctx +// +// let lastClauseIsSingleLine = +// Queue.rev ctxAfterMatch.WriterEvents +// |> Seq.skipWhile (fun e -> +// match e with +// | RestoreIndent _ +// | RestoreAtColumn _ -> true +// | _ -> false) +// // In case the last clause was multiline an UnIndent event should follow +// |> Seq.tryHead +// |> fun e -> +// match e with +// | Some(UnIndentBy _) -> false +// | _ -> true +// +// if lastClauseIsSingleLine then +// ctxAfterMatch +// else +// autoParenthesisIfExpressionExceedsPageWidth (genExpr node.LeftHandSide) ctx +// | lhsExpr -> genExpr lhsExpr ctx +// +// atCurrentColumn ( +// genLhs +// +> sepNln +// +> genSingleTextNode node.Operator +// +> sepNlnWhenWriteBeforeNewlineNotEmpty +// +> sepSpace +// +> genExprInMultilineInfixExpr node.RightHandSide +// ) + +// let genExprInMultilineInfixExpr (e: Expr) = +// match e with +// | Expr.CompExprBody node -> +// let areLetOrUseStatementsEndingWithOtherStatement = +// node.Statements +// |> List.mapWithLast +// (function +// | ComputationExpressionStatement.LetOrUseStatement _ -> true +// | _ -> false) +// (function +// | ComputationExpressionStatement.OtherStatement _ -> true +// | _ -> false) +// |> List.reduce (&&) +// +// if not areLetOrUseStatementsEndingWithOtherStatement then +// genExpr e +// else +// colWithNlnWhenMappedNodeIsMultiline +// true +// ComputationExpressionStatement.Node +// (fun ces -> +// match ces with +// | ComputationExpressionStatement.LetOrUseStatement letOrUseNode -> +// let genIn = +// match letOrUseNode.In with +// | None -> !- "in" +// | Some inNode -> genSingleTextNode inNode +// +// genBinding letOrUseNode.Binding +> sepSpace +> genIn +> sepSpace +// |> genNode letOrUseNode +// | ComputationExpressionStatement.OtherStatement otherNode -> genExpr otherNode +// | _ -> failwith "unexpected ComputationExpressionStatement") +// node.Statements +// |> atCurrentColumn +// |> genNode node +// | Expr.Paren parenNode -> +// match parenNode.Expr with +// | Expr.Match _ as mex -> +// fun ctx -> +// if ctx.Config.MultiLineLambdaClosingNewline then +// genNode +// parenNode +// (genSingleTextNode parenNode.OpeningParen +// +> indentSepNlnUnindent (genExpr mex) +// +> sepNln +// +> genSingleTextNode parenNode.ClosingParen) +// ctx +// else +// genNode +// parenNode +// (genSingleTextNode parenNode.OpeningParen +// +> atCurrentColumnIndent (genExpr mex) +// +> genSingleTextNode parenNode.ClosingParen) +// ctx +// // | Expr.InfixApp infixNode -> +// // match infixNode.LeftHandSide with +// // | Expr.Chain _ -> atCurrentColumnIndent (genExpr e) +// // | _ -> genExpr e +// | Expr.Chain _ +// | Expr.Record _ -> atCurrentColumnIndent (genExpr e) +// | _ -> genExpr e +// | Expr.MatchLambda matchLambdaNode -> +// genSingleTextNode matchLambdaNode.Function +// +> indentSepNlnUnindent (genClauses matchLambdaNode.Clauses) +// |> genNode matchLambdaNode +// | Expr.Record _ -> atCurrentColumnIndent (genExpr e) +// | _ -> genExpr e let genKeepIdentIfThenElse (ifKeyword: Node) (elseKeyword: Node) (e: Expr) ctx = let exprNode = Expr.Node e diff --git a/src/Fantomas.Core/Selection.fs b/src/Fantomas.Core/Selection.fs index 66d4ad3400..7bf0403041 100644 --- a/src/Fantomas.Core/Selection.fs +++ b/src/Fantomas.Core/Selection.fs @@ -222,12 +222,12 @@ let mkTreeWithSingleNode (node: Node) : TreeForSelection = | :? ExprPrefixAppNode as node -> let expr = Expr.PrefixApp node mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) - | :? ExprSameInfixAppsNode as node -> - let expr = Expr.SameInfixApps node - mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) - | :? ExprInfixAppNode as node -> - let expr = Expr.InfixApp node - mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) + // | :? ExprSameInfixAppsNode as node -> + // let expr = Expr.SameInfixApps node + // mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) + // | :? ExprInfixAppNode as node -> + // let expr = Expr.InfixApp node + // mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) | :? ExprIndexWithoutDotNode as node -> let expr = Expr.IndexWithoutDot node mkOakFromModuleDecl (ModuleDecl.DeclExpr expr) diff --git a/src/Fantomas.Core/SyntaxOak.fs b/src/Fantomas.Core/SyntaxOak.fs index 5d2de5a896..8d092bd959 100644 --- a/src/Fantomas.Core/SyntaxOak.fs +++ b/src/Fantomas.Core/SyntaxOak.fs @@ -645,10 +645,10 @@ type ExprLazyNode(lazyWord: SingleTextNode, expr: Expr, range) = member val LazyWord = lazyWord member val Expr = expr - member val ExprIsInfix = - match Expr.Node expr with - | :? InfixApp -> true - | _ -> false + member val ExprIsInfix = false +// match Expr.Node expr with +// | :? InfixApp -> true +// | _ -> false type ExprSingleNode(leading: SingleTextNode, addSpace: bool, supportsStroustrup: bool, expr: Expr, range) = inherit NodeBase(range) @@ -1159,11 +1159,11 @@ type ExprPrefixAppNode(operator: SingleTextNode, expr: Expr, range) = member val Operator = operator member val Expr = expr -type InfixApp = interface end - +// type InfixApp = interface end +// type ExprSameInfixAppsNode(leadingExpr: Expr, subsequentExpressions: (SingleTextNode * Expr) list, range) = inherit NodeBase(range) - interface InfixApp + // interface InfixApp override val Children: Node array = let xs = @@ -1176,7 +1176,7 @@ type ExprSameInfixAppsNode(leadingExpr: Expr, subsequentExpressions: (SingleText type ExprInfixAppNode(lhs: Expr, operator: SingleTextNode, rhs: Expr, range) = inherit NodeBase(range) - interface InfixApp + // interface InfixApp override val Children: Node array = [| yield Expr.Node lhs; yield operator; yield Expr.Node rhs |] member val LeftHandSide = lhs diff --git a/src/Fantomas.Core/Trivia.fs b/src/Fantomas.Core/Trivia.fs index 2c963cb350..c7d3f19bb6 100644 --- a/src/Fantomas.Core/Trivia.fs +++ b/src/Fantomas.Core/Trivia.fs @@ -180,8 +180,8 @@ let rec visitLastChildNode (node: Node) : Node = | :? ExprIfThenElseNode | :? ExprIfThenElifNode | :? ExprAppNode - | :? ExprSameInfixAppsNode - | :? ExprInfixAppNode + // | :? ExprSameInfixAppsNode + // | :? ExprInfixAppNode | :? ExprLambdaNode | :? ExprLetOrUseNode | :? ExprLetOrUseBangNode