Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Feliz style #930

Merged
merged 4 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions src/Fantomas.Tests/ElmishTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,145 @@ let view dispatch model =
]
]
"""

[<Test>]
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" ]
"""

[<Test>]
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"
]
"""

[<Test>]
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"
]
]
"""

[<Test>]
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")
"""

[<Test>]
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" ]
]
"""
54 changes: 39 additions & 15 deletions src/Fantomas/CodePrinter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
2 changes: 2 additions & 0 deletions src/Fantomas/FormatConfig.fs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type FormatConfig =
NewlineBetweenTypeDefinitionAndMembers: bool
KeepIfThenInSameLine : bool
MaxElmishWidth: Num
SingleArgumentWebMode: bool
/// Prettyprinting based on ASTs only
StrictMode : bool }

Expand Down Expand Up @@ -65,6 +66,7 @@ type FormatConfig =
MultilineBlockBracketsOnSameColumn = false
KeepIfThenInSameLine = false
MaxElmishWidth = 40
SingleArgumentWebMode = false
NewlineBetweenTypeDefinitionAndMembers = false
StrictMode = false }

Expand Down
7 changes: 3 additions & 4 deletions src/Fantomas/SourceParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions src/Fantomas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
"MaxElmishWidth": {
"type": "integer"
},
"SingleArgumentWebMode": {
"type": "boolean"
},
"StrictMode": {
"type": "boolean"
}
Expand Down