diff --git a/parser/src/AST/Expression.hs b/parser/src/AST/Expression.hs index 6d6816f36..c329cfb63 100644 --- a/parser/src/AST/Expression.hs +++ b/parser/src/AST/Expression.hs @@ -59,7 +59,7 @@ data Expr' | AccessFunction LowercaseIdentifier | Lambda [(Comments, Pattern.Pattern)] Comments Expr Bool - | If IfClause [(Comments, IfClause)] (Comments, Expr) + | If IfClause [(Comments, IfClause)] (Comments, Expr) Multiline | Let [LetDeclaration] Comments Expr | Case (Commented Expr, Bool) [(Commented Pattern.Pattern, (Comments, Expr))] diff --git a/parser/src/AST/Json.hs b/parser/src/AST/Json.hs index 079cb473c..da9fde759 100644 --- a/parser/src/AST/Json.hs +++ b/parser/src/AST/Json.hs @@ -373,7 +373,7 @@ instance ToJSON Expr where , ("body", showJSON body) ] - If (Commented _ cond' _, Commented _ thenBody' _) rest' (_, elseBody) -> + If (Commented _ cond' _, Commented _ thenBody' _) rest' (_, elseBody) _ -> let ifThenElse :: Expr -> Expr -> [(Comments, IfClause)] -> JSValue ifThenElse cond thenBody rest = diff --git a/parser/src/Parse/Expression.hs b/parser/src/Parse/Expression.hs index 6df39a3e5..07df5d043 100644 --- a/parser/src/Parse/Expression.hs +++ b/parser/src/Parse/Expression.hs @@ -191,11 +191,14 @@ ifExpr elmVersion = >> whitespace in do - first <- ifClause elmVersion - rest <- many (try $ (,) <$> elseKeyword <*> ifClause elmVersion) - final <- (,) <$> elseKeyword <*> expr elmVersion - - return $ E.If first rest final + (first, firstMultiline) <- trackNewline $ ifClause elmVersion + (rest, restMultiline) <- trackNewline $ many (try $ (,) <$> elseKeyword <*> ifClause elmVersion) + (final, finalMultiline) <- trackNewline $ (,) <$> elseKeyword <*> expr elmVersion + + return $ E.If first rest final $ + case (firstMultiline, restMultiline, finalMultiline) of + (JoinAll, JoinAll, JoinAll) -> JoinAll + _ -> SplitAll ifClause :: ElmVersion -> IParser E.IfClause diff --git a/src/AST/MapExpr.hs b/src/AST/MapExpr.hs index d6035ea0c..6a9cce143 100644 --- a/src/AST/MapExpr.hs +++ b/src/AST/MapExpr.hs @@ -81,8 +81,8 @@ instance MapExpr Expr' where AccessFunction _ -> expr Lambda params pre body multi -> Lambda params pre (mapExpr f body) multi - If c1 elseIfs els -> - If (mapExpr f c1) (mapExpr f elseIfs) (mapExpr f els) + If c1 elseIfs els multiline -> + If (mapExpr f c1) (mapExpr f elseIfs) (mapExpr f els) multiline Let decls pre body -> Let (mapExpr f decls) pre body Case cond branches -> diff --git a/src/ElmFormat/Render/Box.hs b/src/ElmFormat/Render/Box.hs index ab0d96660..9213f5d0d 100644 --- a/src/ElmFormat/Render/Box.hs +++ b/src/ElmFormat/Render/Box.hs @@ -1407,57 +1407,9 @@ formatExpression' elmVersion importInfo context aexpr = (fmap (formatPreCommentedExpression elmVersion importInfo SpaceSeparated) args) |> expressionParens SpaceSeparated context - AST.Expression.If if' elseifs (elsComments, els) -> - let - opening key cond = - case (key, cond) of - (SingleLine key', SingleLine cond') -> - line $ row - [ key' - , space - , cond' - , space - , keyword "then" - ] - _ -> - stack1 - [ key - , cond |> indent - , line $ keyword "then" - ] - - formatIf (cond, body) = - stack1 - [ opening (line $ keyword "if") $ formatCommentedExpression elmVersion importInfo SyntaxSeparated cond - , indent $ formatCommented_ True (formatExpression elmVersion importInfo SyntaxSeparated) body - ] - - formatElseIf (ifComments, (cond, body)) = - let - key = - case (formatHeadCommented id (ifComments, line $ keyword "if")) of - SingleLine key' -> - line $ row [ keyword "else", space, key' ] - key' -> - stack1 - [ line $ keyword "else" - , key' - ] - in - stack1 - [ blankLine - , opening key $ formatCommentedExpression elmVersion importInfo SyntaxSeparated cond - , indent $ formatCommented_ True (formatExpression elmVersion importInfo SyntaxSeparated) body - ] - in - formatIf if' - |> andThen (map formatElseIf elseifs) - |> andThen - [ blankLine - , line $ keyword "else" - , indent $ formatCommented_ True (formatExpression elmVersion importInfo SyntaxSeparated) (AST.Commented elsComments els []) - ] - |> expressionParens AmbiguousEnd context + AST.Expression.If if' elseifs els multiline -> + formatIfExpression elmVersion importInfo if' elseifs els multiline + |> expressionParens AmbiguousEnd context AST.Expression.Let defs bodyComments expr -> let @@ -1595,6 +1547,112 @@ formatExpression' elmVersion importInfo context aexpr = ] +formatIfExpression :: + ElmVersion + -> ImportInfo + -> AST.Expression.IfClause + -> [(AST.Comments, AST.Expression.IfClause)] + -> (AST.Comments, AST.Expression.Expr) + -> AST.Multiline + -> Box +formatIfExpression elmVersion importInfo if' elseifs (elsComments, els) multiline = + let + (cond, (AST.Commented preThen thenExpr postThen)) = + if' + + cond' = + formatIfOpening (line $ keyword "if") $ + formatCommentedExpression elmVersion importInfo SyntaxSeparated cond + + then' = + concat $ + [ Maybe.maybeToList $ formatComments preThen + , [ formatExpression elmVersion importInfo SyntaxSeparated thenExpr ] + , Maybe.maybeToList $ formatComments postThen + ] + + else' = + (Maybe.maybeToList $ formatComments elsComments) + ++ [ formatExpression elmVersion importInfo SyntaxSeparated els ] + in + case + ( multiline + , isLine cond' + , allSingles then' + , fmap (formatElseIf elmVersion importInfo) elseifs + , allSingles else' + ) + of + (AST.JoinAll, Right singleCond, Right singleThens, [], Right singleElses) -> + line $ row $ concat + [ [singleCond, space] + , List.intersperse space singleThens + , [ space, keyword "else", space ] + , List.intersperse space singleElses + ] + + (_, ifCond, thenBody, elseIfs', elseBody) -> + stack1 + [ boxOrLineToBox ifCond + , indent $ boxesOrLinesToBox True thenBody + ] + |> andThen elseIfs' + |> andThen + [ blankLine + , line $ keyword "else" + , indent $ boxesOrLinesToBox True elseBody + ] + + +formatIfOpening :: Box -> Box -> Box +formatIfOpening key cond = + case (key, cond) of + (SingleLine key', SingleLine cond') -> + line $ row [ key', space, cond', space, keyword "then" ] + + _ -> + stack1 + [ key + , cond |> indent + , line $ keyword "then" + ] + + +formatElseIf :: ElmVersion -> ImportInfo -> (AST.Comments, AST.Expression.IfClause) -> Box +formatElseIf elmVersion importInfo (ifComments, (cond', body')) = + let + key = + case (formatHeadCommented id (ifComments, line $ keyword "if")) of + SingleLine key' -> + line $ row [ keyword "else", space, key' ] + key' -> + stack1 + [ line $ keyword "else" + , key' + ] + in + stack1 + [ blankLine + , formatIfOpening key $ formatCommentedExpression elmVersion importInfo SyntaxSeparated cond' + , indent $ formatCommented_ True (formatExpression elmVersion importInfo SyntaxSeparated) body' + ] + + +boxOrLineToBox :: Either Box Line -> Box +boxOrLineToBox boxOrLine = + case boxOrLine of + Right singleLine -> line singleLine + Left box -> box + + +boxesOrLinesToBox :: Bool -> Either [Box] [Line] -> Box +boxesOrLinesToBox forceMultiline boxesOrLines = + ElmStructure.forceableSpaceSepOrStack1 forceMultiline $ + case boxesOrLines of + Right singleLines -> fmap line singleLines + Left boxes -> boxes + + formatCommentedExpression :: ElmVersion -> ImportInfo -> ExpressionContext -> AST.Commented AST.Expression.Expr -> Box formatCommentedExpression elmVersion importInfo context (AST.Commented pre e post) = let diff --git a/tests/Parse/ExpressionTest.hs b/tests/Parse/ExpressionTest.hs index 0d91dbe63..7322f4100 100644 --- a/tests/Parse/ExpressionTest.hs +++ b/tests/Parse/ExpressionTest.hs @@ -259,10 +259,10 @@ tests = ] , testGroup "if statement" - [ example "" "if x then y else z" $ at 1 1 1 19 (If (Commented [] (at 1 4 1 5 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [],Commented [] (at 1 11 1 12 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) []) [] ([],at 1 18 1 19 (VarExpr (VarRef [] $ LowercaseIdentifier "z")))) - , example "comments" "if{-A-}x{-B-}then{-C-}y{-D-}else{-E-}if{-F-}x_{-G-}then{-H-}y_{-I-}else{-J-}z" $ at 1 1 1 78 (If (Commented [BlockComment ["A"]] (at 1 8 1 9 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [BlockComment ["B"]],Commented [BlockComment ["C"]] (at 1 23 1 24 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) [BlockComment ["D"]]) [([BlockComment ["E"]],(Commented [BlockComment ["F"]] (at 1 45 1 47 (VarExpr (VarRef [] $ LowercaseIdentifier "x_"))) [BlockComment ["G"]],Commented [BlockComment ["H"]] (at 1 61 1 63 (VarExpr (VarRef [] $ LowercaseIdentifier "y_"))) [BlockComment ["I"]]))] ([BlockComment ["J"]],at 1 77 1 78 (VarExpr (VarRef [] $ LowercaseIdentifier "z")))) - , example "else if" "if x1 then y1 else if x2 then y2 else if x3 then y3 else z" $ at 1 1 1 59 (If (Commented [] (at 1 4 1 6 (VarExpr (VarRef [] $ LowercaseIdentifier "x1"))) [],Commented [] (at 1 12 1 14 (VarExpr (VarRef [] $ LowercaseIdentifier "y1"))) []) [([],(Commented [] (at 1 23 1 25 (VarExpr (VarRef [] $ LowercaseIdentifier "x2"))) [],Commented [] (at 1 31 1 33 (VarExpr (VarRef [] $ LowercaseIdentifier "y2"))) [])),([],(Commented [] (at 1 42 1 44 (VarExpr (VarRef [] $ LowercaseIdentifier "x3"))) [],Commented [] (at 1 50 1 52 (VarExpr (VarRef [] $ LowercaseIdentifier "y3"))) []))] ([],at 1 58 1 59 (VarExpr (VarRef [] $ LowercaseIdentifier "z")))) - , example "newlines" "if\n x\n then\n y\n else\n z" $ at 1 1 6 3 (If (Commented [] (at 2 2 2 3 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [],Commented [] (at 4 2 4 3 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) []) [] ([],at 6 2 6 3 (VarExpr (VarRef [] $ LowercaseIdentifier "z")))) + [ example "" "if x then y else z" $ at 1 1 1 19 (If (Commented [] (at 1 4 1 5 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [],Commented [] (at 1 11 1 12 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) []) [] ([],at 1 18 1 19 (VarExpr (VarRef [] $ LowercaseIdentifier "z"))) JoinAll) + , example "comments" "if{-A-}x{-B-}then{-C-}y{-D-}else{-E-}if{-F-}x_{-G-}then{-H-}y_{-I-}else{-J-}z" $ at 1 1 1 78 (If (Commented [BlockComment ["A"]] (at 1 8 1 9 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [BlockComment ["B"]],Commented [BlockComment ["C"]] (at 1 23 1 24 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) [BlockComment ["D"]]) [([BlockComment ["E"]],(Commented [BlockComment ["F"]] (at 1 45 1 47 (VarExpr (VarRef [] $ LowercaseIdentifier "x_"))) [BlockComment ["G"]],Commented [BlockComment ["H"]] (at 1 61 1 63 (VarExpr (VarRef [] $ LowercaseIdentifier "y_"))) [BlockComment ["I"]]))] ([BlockComment ["J"]],at 1 77 1 78 (VarExpr (VarRef [] $ LowercaseIdentifier "z"))) JoinAll) + , example "else if" "if x1 then y1 else if x2 then y2 else if x3 then y3 else z" $ at 1 1 1 59 (If (Commented [] (at 1 4 1 6 (VarExpr (VarRef [] $ LowercaseIdentifier "x1"))) [],Commented [] (at 1 12 1 14 (VarExpr (VarRef [] $ LowercaseIdentifier "y1"))) []) [([],(Commented [] (at 1 23 1 25 (VarExpr (VarRef [] $ LowercaseIdentifier "x2"))) [],Commented [] (at 1 31 1 33 (VarExpr (VarRef [] $ LowercaseIdentifier "y2"))) [])),([],(Commented [] (at 1 42 1 44 (VarExpr (VarRef [] $ LowercaseIdentifier "x3"))) [],Commented [] (at 1 50 1 52 (VarExpr (VarRef [] $ LowercaseIdentifier "y3"))) []))] ([],at 1 58 1 59 (VarExpr (VarRef [] $ LowercaseIdentifier "z"))) JoinAll) + , example "newlines" "if\n x\n then\n y\n else\n z" $ at 1 1 6 3 (If (Commented [] (at 2 2 2 3 (VarExpr (VarRef [] $ LowercaseIdentifier "x"))) [],Commented [] (at 4 2 4 3 (VarExpr (VarRef [] $ LowercaseIdentifier "y"))) []) [] ([],at 6 2 6 3 (VarExpr (VarRef [] $ LowercaseIdentifier "z"))) SplitAll) ] , testGroup "let statement" diff --git a/tests/test-files/good/Elm-0.19/AllSyntax/Expressions.elm b/tests/test-files/good/Elm-0.19/AllSyntax/Expressions.elm index 96e70aabb..d18e20101 100644 --- a/tests/test-files/good/Elm-0.19/AllSyntax/Expressions.elm +++ b/tests/test-files/good/Elm-0.19/AllSyntax/Expressions.elm @@ -273,6 +273,16 @@ lambdaWithMultilinePattern = ifStatement = let a = + if True then 1 else 2 + + b = + if True then + 1 + + else + 2 + + c = if True then 1 @@ -282,44 +292,100 @@ ifStatement = else 3 - b = - if {- C -} True {- D -} then - {- E -} + d = + if {- A -} True {- B -} then {- C -} 1 {- D -} else {- E -} 2 + + e = + if {- A -} {- B -} True {- C -} {- D -} then {- E -} {- F -} 1 {- G -} {- H -} else {- I -} {- J -} 2 + + f = + if {- A -} True {- B -} then + {- C -} 1 - {- F -} + {- D -} + + else {- E -} if {- F -} False {- G -} then + {- H -} + 2 + {- I -} - else {- G -} if {- H -} False {- I -} then + else {- J -} + 3 + + g = + if {- A -} {- B -} True {- C -} {- D -} then + {- E -} {- F -} + 1 + {- G -} {- H -} + + else {- I -} {- J -} if {- K -} {- L -} False {- M -} {- N -} then + {- O -} {- P -} 2 - {- K -} + {- Q -} {- R -} else - {- L -} + {- S -} {- T -} 3 - c = + h = if + --A + True + --B + then --C + 1 + --D + + else + --E + if + --F + False + --G + then + --H + 2 + --I + + else + --J + 3 + + i = + if + --A + --B True + --C --D then --E - 1 --F + 1 + --G + --H else - --G + --I + --J if - --H + --K + --L False - --I + --M + --N then - --J + --O + --P 2 - --K + --Q + --R else - --L + --S + --T 3 in {} diff --git a/tests/test-files/transform/Elm-0.18/Examples.elm b/tests/test-files/transform/Elm-0.18/Examples.elm index 53d6f67f7..259e2e5ea 100644 --- a/tests/test-files/transform/Elm-0.18/Examples.elm +++ b/tests/test-files/transform/Elm-0.18/Examples.elm @@ -4,7 +4,8 @@ ratio = graphHeight / (if range == 0 then 0.1 else toFloat range) -- foo=(case x of {True->1;False->3}) -bar = (if if a then True else False then "a" else "b") +bar = (if if a then + True else False then "a" else "b") multilineList = [1,2,3 ] diff --git a/tests/test-files/transform/Elm-0.18/Examples.formatted.elm b/tests/test-files/transform/Elm-0.18/Examples.formatted.elm index dbafc1d62..7a4a6086e 100644 --- a/tests/test-files/transform/Elm-0.18/Examples.formatted.elm +++ b/tests/test-files/transform/Elm-0.18/Examples.formatted.elm @@ -2,13 +2,7 @@ module Main exposing (bar, multilineList, ratio) ratio = - graphHeight - / (if range == 0 then - 0.1 - - else - toFloat range - ) + graphHeight / (if range == 0 then 0.1 else toFloat range) diff --git a/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.elm b/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.elm new file mode 100644 index 000000000..b75e6f61e --- /dev/null +++ b/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.elm @@ -0,0 +1 @@ +x = if True then 1 else if False then 2 else 3 diff --git a/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.formatted.elm b/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.formatted.elm new file mode 100644 index 000000000..d7b7e2d6c --- /dev/null +++ b/tests/test-files/transform/Elm-0.19/IfElseIfAlwaysMultiLine.formatted.elm @@ -0,0 +1,12 @@ +module Main exposing (x) + + +x = + if True then + 1 + + else if False then + 2 + + else + 3