From db526ab35133350c0d991d024475a081754deb88 Mon Sep 17 00:00:00 2001 From: Florian Verdonck Date: Thu, 25 Jun 2020 21:44:57 +0200 Subject: [PATCH] Add support for Feliz style (#930) * Support Feliz style * Refactored Feliz expressions. Fixes #927 * Added SingleArgumentWebMode to schema.json * Bump to alpha 011 --- RELEASE_NOTES.md | 2 +- .../Fantomas.CoreGlobalTool.Tests.fsproj | 2 +- .../Fantomas.CoreGlobalTool.fsproj | 2 +- src/Fantomas.Tests/ElmishTests.fs | 142 ++++++++++++++++++ src/Fantomas.Tests/Fantomas.Tests.fsproj | 2 +- src/Fantomas/CodePrinter.fs | 54 +++++-- src/Fantomas/Fantomas.fsproj | 2 +- src/Fantomas/FormatConfig.fs | 2 + src/Fantomas/SourceParser.fs | 7 +- src/Fantomas/schema.json | 3 + 10 files changed, 194 insertions(+), 24 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3aebd4bf0e..7ca3ff2430 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,4 @@ -### 4.0.0-alpha-010 - 06/2020 +### 4.0.0-alpha-011 - 06/2020 * WIP for [#705](https://github.com/fsprojects/fantomas/issues/705) * FCS 36 diff --git a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj index 1e402e07c1..2013bbe68a 100644 --- a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj +++ b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 false false - 4.0.0-alpha-010 + 4.0.0-alpha-011 FS0988 diff --git a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj index 59ba23a699..fe298a0430 100644 --- a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj +++ b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 fantomas True - 4.0.0-alpha-010 + 4.0.0-alpha-011 fantomas-tool diff --git a/src/Fantomas.Tests/ElmishTests.fs b/src/Fantomas.Tests/ElmishTests.fs index e3a7fa728e..13ba7304ba 100644 --- a/src/Fantomas.Tests/ElmishTests.fs +++ b/src/Fantomas.Tests/ElmishTests.fs @@ -569,3 +569,145 @@ let view dispatch model = ] ] """ + +[] +let ``short feliz element`` () = + formatSourceString false """let a = + Html.h1 [ prop.text "some title" ] +""" config + |> prepend newline + |> should equal """ +let a = Html.h1 [ prop.text "some title" ] +""" + +[] +let ``multiline feliz element`` () = + formatSourceString false """let a = + Html.button [ + prop.style [ style.marginLeft 5 ] + prop.onClick (fun _ -> setCount(count - 1)) + prop.text "Decrement" + ] +""" { config with SingleArgumentWebMode = true } + |> prepend newline + |> should equal """ +let a = + Html.button [ + prop.style [ style.marginLeft 5 ] + prop.onClick (fun _ -> setCount (count - 1)) + prop.text "Decrement" + ] +""" + +[] +let ``nested feliz elements`` () = + formatSourceString false """let a = + Html.div [ + Html.h1 [ prop.text "short" ] + Html.button [ + prop.style [ style.marginRight 5 ] + prop.onClick (fun _ -> setCount(count + 1)) + prop.text "Increment" + ] + ] +""" { config with SingleArgumentWebMode = true } + |> prepend newline + |> should equal """ +let a = + Html.div [ + Html.h1 [ prop.text "short" ] + Html.button [ + prop.style [ style.marginRight 5 ] + prop.onClick (fun _ -> setCount (count + 1)) + prop.text "Increment" + ] + ] +""" + +[] +let ``feliz counter sample`` () = + formatSourceString false """module App + +open Feliz + +let counter = React.functionComponent(fun () -> + let (count, setCount) = React.useState(0) + Html.div [ + Html.button [ + prop.style [ style.marginRight 5 ] + prop.onClick (fun _ -> setCount(count + 1)) + prop.text "Increment" + ] + + Html.button [ + prop.style [ style.marginLeft 5 ] + prop.onClick (fun _ -> setCount(count - 1)) + prop.text "Decrement" + ] + + Html.h1 count + ]) + +open Browser.Dom + +ReactDOM.render(counter, document.getElementById "root") +""" { config with SingleArgumentWebMode = true } + |> prepend newline + |> should equal """ +module App + +open Feliz + +let counter = + React.functionComponent (fun () -> + let (count, setCount) = React.useState (0) + Html.div [ + Html.button [ + prop.style [ style.marginRight 5 ] + prop.onClick (fun _ -> setCount (count + 1)) + prop.text "Increment" + ] + + Html.button [ + prop.style [ style.marginLeft 5 ] + prop.onClick (fun _ -> setCount (count - 1)) + prop.text "Decrement" + ] + + Html.h1 count + ]) + +open Browser.Dom + +ReactDOM.render (counter, document.getElementById "root") +""" + +[] +let ``feliz syntax`` () = + formatSourceString false """ +Html.h1 42 + +Html.div "Hello there!" + +Html.div [ Html.h1 "So lightweight" ] + +Html.ul [ + Html.li "One" + Html.li [ Html.strong "Two" ] + Html.li [ Html.em "Three" ] +] +""" { config with SingleArgumentWebMode = true } + |> prepend newline + |> should equal """ +Html.h1 42 + +Html.div "Hello there!" + +Html.div [ Html.h1 "So lightweight" ] + +Html.ul [ + Html.li "One" + Html.li [ Html.strong "Two" ] + Html.li [ Html.em "Three" ] +] +""" \ No newline at end of file diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index b30444531c..3232f1ef42 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -1,7 +1,7 @@ - 4.0.0-alpha-010 + 4.0.0-alpha-011 FS0988 netcoreapp3.1 diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 476605ef84..786ac61dd2 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -825,23 +825,47 @@ and genExpr astContext synExpr = let sepCloseT = tokN synExpr.Range "RPAREN" sepCloseT match synExpr with - | ElmishReactWithoutChildren(identifier, attributes) -> + | ElmishReactWithoutChildren(identifier, isArray, children) -> fun ctx -> - let maxRemainingArrayLength = ctx.Config.MaxElmishWidth - identifier.Length - let ctx' = - { ctx with Config = { ctx.Config with - MaxArrayOrListWidth = maxRemainingArrayLength - // override user setting to get original fantomas formatting - MultilineBlockBracketsOnSameColumn = false } } - (!- identifier - +> sepSpace - +> genExpr astContext attributes - +> fun cty -> - // reset the config with original values - { cty with Config = { cty.Config with - MaxArrayOrListWidth = ctx.Config.MaxArrayOrListWidth - MultilineBlockBracketsOnSameColumn = ctx.Config.MultilineBlockBracketsOnSameColumn } }) ctx' + let shortExpression = + let noChildren = + ifElse isArray sepOpenAFixed sepOpenLFixed + +> ifElse isArray sepCloseAFixed sepCloseLFixed + + let genChildren = + ifElse isArray sepOpenA sepOpenL + +> col sepSemi children (genExpr astContext) + +> ifElse isArray sepCloseA sepCloseL + !- identifier + +> sepSpace + +> ifElse (List.isEmpty children) noChildren genChildren + + let elmishExpression = + !- identifier + +> sepSpace + +> ifElse isArray sepOpenA sepOpenL + +> atCurrentColumn (col sepNln children (genExpr astContext)) + +> ifElse isArray sepCloseA sepCloseL + + let felizExpression = + atCurrentColumn (!- identifier + +> sepSpace + +> ifElse isArray sepOpenAFixed sepOpenLFixed + +> indent + +> sepNln + +> col sepNln children (genExpr astContext) + +> unindent + +> sepNln + +> ifElse isArray sepCloseAFixed sepCloseLFixed) + + let multilineExpression = ifElse ctx.Config.SingleArgumentWebMode felizExpression elmishExpression + + isShortExpression + ctx.Config.MaxElmishWidth + shortExpression + multilineExpression + ctx | ElmishReactWithChildren((identifier,_,_), attributes, (isArray,children)) -> let genChildren isShort = diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj index dfb0da4a0c..81172ba8fd 100644 --- a/src/Fantomas/Fantomas.fsproj +++ b/src/Fantomas/Fantomas.fsproj @@ -3,7 +3,7 @@ netstandard2.0 - 4.0.0-alpha-010 + 4.0.0-alpha-011 Source code formatter for F# diff --git a/src/Fantomas/FormatConfig.fs b/src/Fantomas/FormatConfig.fs index 50147e1328..80c709dcdc 100644 --- a/src/Fantomas/FormatConfig.fs +++ b/src/Fantomas/FormatConfig.fs @@ -38,6 +38,7 @@ type FormatConfig = NewlineBetweenTypeDefinitionAndMembers: bool KeepIfThenInSameLine : bool MaxElmishWidth: Num + SingleArgumentWebMode: bool /// Prettyprinting based on ASTs only StrictMode : bool } @@ -65,6 +66,7 @@ type FormatConfig = MultilineBlockBracketsOnSameColumn = false KeepIfThenInSameLine = false MaxElmishWidth = 40 + SingleArgumentWebMode = false NewlineBetweenTypeDefinitionAndMembers = false StrictMode = false } diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index bd92409ed0..6d31d278dc 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1427,10 +1427,9 @@ let isFunctionBinding (p: SynPat) = let (|ElmishReactWithoutChildren|_|) e = match e with - | App(OptVar(ident,_,_), [ArrayOrList(_) as attributes]) -> - Some(ident, attributes) - | App(OptVar(ident,_,_), [ArrayOrListOfSeqExpr(_, CompExpr(_, Sequentials _)) as attributes]) -> - Some(ident, attributes) + | App(OptVar(ident,_,_), [ArrayOrList(isArray, children, _)]) + | App(OptVar(ident,_,_), [ArrayOrListOfSeqExpr(isArray, CompExpr(_, Sequentials children))]) -> + Some(ident, isArray, children) | _ -> None diff --git a/src/Fantomas/schema.json b/src/Fantomas/schema.json index 26fdffdb19..7dcfb7ae72 100644 --- a/src/Fantomas/schema.json +++ b/src/Fantomas/schema.json @@ -74,6 +74,9 @@ "MaxElmishWidth": { "type": "integer" }, + "SingleArgumentWebMode": { + "type": "boolean" + }, "StrictMode": { "type": "boolean" }