From 44a0b206e38cfba2a000fe6e61dd52c5d25d96a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jind=C5=99ich=20Iv=C3=A1nek?= Date: Fri, 18 Jan 2019 19:02:18 +0100 Subject: [PATCH] Dont use let .. in when multiline after "in"or formatting from AST. Should fix #384 (#393) dont use let .. in when formatting from AST --- src/Fantomas.Tests/FormatAstTests.fs | 18 +++++++--- src/Fantomas.Tests/LetBindingTests.fs | 48 +++++++++++++++++++++++++++ src/Fantomas/CodePrinter.fs | 8 +++-- src/Fantomas/Context.fs | 3 ++ src/Fantomas/TokenMatcher.fs | 6 ++-- 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/Fantomas.Tests/FormatAstTests.fs b/src/Fantomas.Tests/FormatAstTests.fs index a22741dd6f..dcb89783ab 100644 --- a/src/Fantomas.Tests/FormatAstTests.fs +++ b/src/Fantomas.Tests/FormatAstTests.fs @@ -4,13 +4,23 @@ open NUnit.Framework open FsUnit open Fantomas.Tests.TestHelper -[] -let ``Format the ast works correctly with no source code``() = +let formatAst code = let inputExp = - "()" |> Input + code |> Input |> toSynExprs |> List.head fromSynExpr inputExp |> function Input x -> x.TrimEnd('\r', '\n') - |> should equal "()" \ No newline at end of file + |> fun s -> s.Replace("\r\n", "\n") + +[] +let ``Format the ast works correctly with no source code``() = + formatAst "()" + |> should equal "()" + +[] +let ``let in should not be used``() = + formatAst "let x = 1 in ()" + |> should equal """let x = 1 +()""" diff --git a/src/Fantomas.Tests/LetBindingTests.fs b/src/Fantomas.Tests/LetBindingTests.fs index 186ca46576..c053d516aa 100644 --- a/src/Fantomas.Tests/LetBindingTests.fs +++ b/src/Fantomas.Tests/LetBindingTests.fs @@ -30,4 +30,52 @@ let f () = let x = 1 // the "in" keyword is available in F# let y = 2 x + y +""" + +[] +let ``multiple let in lines, should remove in, block comment`` () = + let codeSnippet = """ +let f () = + let x = 1 in (* the "in" keyword is available in F# *) + let y = 2 in + x + y +""" + + formatSourceString false codeSnippet config + |> should equal """let f() = + let x = 1 (* the "in" keyword is available in F# *) + let y = 2 + x + y +""" + +[] +let ``multiline let in, should remove in`` () = + let codeSnippet = """ +let f () = + let x = 1 in if true + then x + else x +""" + + formatSourceString false codeSnippet config + |> should equal """let f() = + let x = 1 + if true then x + else x +""" + +[] +let ``multiline let in, should remove in 2`` () = + let codeSnippet = """ +let f () = + let x = 1 in (while true do () + x) +""" + + formatSourceString false codeSnippet config + |> should equal """let f() = + let x = 1 + (while true do + () + x) """ \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index d1f957ac26..7717bc5440 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -658,11 +658,13 @@ and genExpr astContext synExpr = | TypeApp(e, ts) -> genExpr astContext e -- "<" +> col sepComma ts (genType astContext false) -- ">" | LetOrUses(bs, e) -> - let isInSameLine = + let isFromAst (ctx: Context) = ctx.Content = String.Empty + let isInSameLine ctx = match bs with - | [_, LetBinding(ats, px, ao, isInline, isMutable, p, _)] -> p.Range.EndLine = e.Range.StartLine + | [_, LetBinding(ats, px, ao, isInline, isMutable, p, _)] -> + not (isFromAst ctx) && p.Range.EndLine = e.Range.StartLine && not(checkBreakForExpr e) | _ -> false - atCurrentColumn (genLetOrUseList astContext bs +> ifElse isInSameLine (!- " in ") sepNln +> genExpr astContext e) + atCurrentColumn (genLetOrUseList astContext bs +> ifElseCtx isInSameLine (!- " in ") sepNln +> genExpr astContext e) // Could customize a bit if e is single line | TryWith(e, cs) -> diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 486e582434..16d01236ff 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -202,6 +202,9 @@ let internal optPre (f2 : _ -> Context) (f1 : Context -> _) o f (ctx : Context) let internal ifElse b (f1 : Context -> Context) f2 (ctx : Context) = if b then f1 ctx else f2 ctx +let internal ifElseCtx cond (f1 : Context -> Context) f2 (ctx : Context) = + if cond ctx then f1 ctx else f2 ctx + /// Repeat application of a function n times let internal rep n (f : Context -> Context) (ctx : Context) = [1..n] |> List.fold (fun c _ -> f c) ctx diff --git a/src/Fantomas/TokenMatcher.fs b/src/Fantomas/TokenMatcher.fs index f8a9329073..c0d76b8ef0 100644 --- a/src/Fantomas/TokenMatcher.fs +++ b/src/Fantomas/TokenMatcher.fs @@ -694,8 +694,10 @@ let integrateComments (config:Fantomas.FormatConfig.FormatConfig) compilationDef | (Marked(inToken,_,_)::oldTokens), (NewLine newTokText :: moreNewTokens) -> Debug.WriteLine(sprintf "emitting newline in new tokens '%s'" newTokText) let nextOldTokens = - match (inToken) with - | Tok(fsInToken,_) when (fsInToken.TokenName = "IN") -> + match (inToken, oldTokens) with + | Tok(fsInToken,_), (WhiteSpaceTokens (_, LineCommentToken false _ :: _)) + | Tok(fsInToken,_), (WhiteSpaceTokens (_, BlockCommentToken _ :: _)) + when (fsInToken.TokenName = "IN") -> // find tokens before newline in old source let tokensBeforeNewline = oldTokens