Skip to content

Commit

Permalink
Create custom range for brackets in Elmish elements inside of full Sy…
Browse files Browse the repository at this point in the history
…nExpr range. Fixes #1347. (#1495)
  • Loading branch information
nojaf committed Feb 27, 2021
1 parent 83ff34e commit 20a09de
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 21 deletions.
199 changes: 199 additions & 0 deletions src/Fantomas.Tests/ElmishTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,3 +1091,202 @@ Gen.frequency [
genSubSynPat
] //
"""

[<Test>]
let ``don't repeat comment in nested Elmish element, 1347`` () =
formatSourceString
false
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [
prop.className "navbar-item"
]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
]
]
]
]
"""
config
|> prepend newline
|> should
equal
"""
let html =
Html.div [ prop.className "navbar-menu"
prop.children [ Html.div [ prop.className "navbar-start"
prop.children [ Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
] ] ] ]
"""

[<Test>]
let ``don't repeat comment in nested Elmish element, idempotent check`` () =
formatSourceString
false
"""
let html2 =
Html.div [ prop.className "navbar-menu"
prop.children [ Html.div [ prop.className "navbar-start"
prop.children [ Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
] ] ] ]
"""
config
|> prepend newline
|> should
equal
"""
let html2 =
Html.div [ prop.className "navbar-menu"
prop.children [ Html.div [ prop.className "navbar-start"
prop.children [ Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
] ] ] ]
"""

[<Test>]
let ``don't repeat comment in nested Elmish element, single element mode`` () =
formatSourceString
false
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [
prop.className "navbar-item"
]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
]
]
]
]
"""
{ config with
SingleArgumentWebMode = true }
|> prepend newline
|> should
equal
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
]
]
]
]
"""

[<Test>]
let ``don't repeat comment in nested Elmish element, single element mode idempotent`` () =
formatSourceString
false
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
]
]
]
]
"""
{ config with
SingleArgumentWebMode = true }
|> prepend newline
|> should
equal
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [ prop.className "navbar-item" ]
(*
Html.a [ prop.className "navbar-item"; prop.href (baseUrl +/ "Files") ] [
prop.text "Files"
]*)
]
]
]
]
"""

[<Test>]
let ``don't repeat comment in nested Elmish element, short block comment`` () =
formatSourceString
false
"""
let html =
Html.div [
prop.className "navbar-menu"
prop.children [
Html.div [
prop.className "navbar-start"
prop.children [
Html.a [
prop.className "navbar-item"
]
(* meh *)
]
]
]
]
"""
config
|> prepend newline
|> should
equal
"""
let html =
Html.div [ prop.className "navbar-menu"
prop.children [ Html.div [ prop.className "navbar-start"
prop.children [ Html.a [ prop.className "navbar-item" ]
(* meh *)
] ] ] ]
"""
61 changes: 45 additions & 16 deletions src/Fantomas/CodePrinter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,18 +1037,32 @@ and genExpr astContext synExpr ctx =

let expr =
match synExpr with
| ElmishReactWithoutChildren (identifier, isArray, children) when (not ctx.Config.DisableElmishSyntax) ->
fun ctx ->
| ElmishReactWithoutChildren (identifier, isArray, children, childrenRange) when
(not ctx.Config.DisableElmishSyntax) ->
fun (ctx: Context) ->
let tokenSize = if isArray then 2 else 1

let openingTokenRange, openTokenType =
ctx.MkRangeWith
(childrenRange.Start.Line, childrenRange.Start.Column)
(childrenRange.Start.Line, (childrenRange.Start.Column + tokenSize)),
(if isArray then LBRACK_BAR else LBRACK)

let closingTokenRange, closingTokenType =
ctx.MkRangeWith
(childrenRange.End.Line, (childrenRange.End.Column - tokenSize))
(childrenRange.End.Line, childrenRange.End.Column),
(if isArray then BAR_RBRACK else RBRACK)

let shortExpression =
let noChildren =
ifElse isArray sepOpenAFixed sepOpenLFixed
+> ifElse isArray sepCloseAFixed sepCloseLFixed
tokN openingTokenRange openTokenType (ifElse isArray sepOpenAFixed sepOpenLFixed)
+> tokN closingTokenRange closingTokenType (ifElse isArray sepCloseAFixed sepCloseLFixed)

let genChildren =
ifElse isArray sepOpenA sepOpenL
tokN openingTokenRange openTokenType (ifElse isArray sepOpenA sepOpenL)
+> col sepSemi children (genExpr astContext)
+> enterNodeTokenByName synExpr.Range (if isArray then BAR_RBRACK else RBRACK)
+> ifElse isArray sepCloseA sepCloseL
+> tokN closingTokenRange closingTokenType (ifElse isArray sepCloseA sepCloseL)

!-identifier
+> sepSpace
Expand All @@ -1057,27 +1071,42 @@ and genExpr astContext synExpr ctx =
let elmishExpression =
!-identifier
+> sepSpace
+> ifElse isArray sepOpenA sepOpenL
+> tokN openingTokenRange openTokenType (ifElse isArray sepOpenA sepOpenL)
+> atCurrentColumn (
col sepNln children (genExpr astContext)
+> enterNodeTokenByName synExpr.Range (if isArray then BAR_RBRACK else RBRACK)
+> onlyIf
(TriviaHelpers.``has content before that matches``
(fun tn -> RangeHelpers.rangeEq tn.Range closingTokenRange)
(function
| Comment (BlockComment _) -> true
| _ -> false)
(Map.tryFindOrEmptyList closingTokenType ctx.TriviaTokenNodes))
sepNln
+> tokN closingTokenRange closingTokenType (ifElse isArray sepCloseA sepCloseL)
)
+> ifElse isArray sepCloseA sepCloseL
+> leaveNodeTokenByName synExpr.Range (if isArray then BAR_RBRACK else RBRACK)

let felizExpression =
let hasBlockCommentBeforeClosingToken =
TriviaHelpers.``has content before that matches``
(fun tn -> RangeHelpers.rangeEq tn.Range closingTokenRange)
(function
| Comment (BlockComment _) -> true
| _ -> false)
(Map.tryFindOrEmptyList closingTokenType ctx.TriviaTokenNodes)

atCurrentColumn (
!-identifier
+> sepSpace
+> ifElse isArray sepOpenAFixed sepOpenLFixed
+> tokN openingTokenRange openTokenType (ifElse isArray sepOpenAFixed sepOpenLFixed)
+> indent
+> sepNln
+> col sepNln children (genExpr astContext)
+> unindent
+> sepNln
+> enterNodeTokenByName synExpr.Range (if isArray then BAR_RBRACK else RBRACK)
+> onlyIf hasBlockCommentBeforeClosingToken (sepNln +> unindent)
+> enterNodeTokenByName closingTokenRange closingTokenType
+> onlyIfNot hasBlockCommentBeforeClosingToken unindent
+> sepNlnUnlessLastEventIsNewline
+> ifElse isArray sepCloseAFixed sepCloseLFixed
+> leaveNodeTokenByName synExpr.Range (if isArray then BAR_RBRACK else RBRACK)
+> leaveNodeTokenByName closingTokenRange closingTokenType
)

let multilineExpression =
Expand Down
1 change: 1 addition & 0 deletions src/Fantomas/Context.fs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ let internal lastWriteEventIsNewline ctx =
(function
| RestoreIndent _
| RestoreAtColumn _
| UnIndentBy _
| Write "" -> true
| _ -> false)
|> Seq.tryHead
Expand Down
10 changes: 5 additions & 5 deletions src/Fantomas/SourceParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1700,11 +1700,11 @@ let isFunctionBinding (p: SynPat) =

let (|ElmishReactWithoutChildren|_|) e =
match e with
| App (OptVar (ident, _, _), [ ArrayOrList (isArray, children, _) ])
| App (OptVar (ident, _, _), [ ArrayOrListOfSeqExpr (isArray, CompExpr (_, Sequentials children)) ]) ->
Some(ident, isArray, children)
| App (OptVar (ident, _, _), [ ArrayOrListOfSeqExpr (isArray, CompExpr (_, singleChild)) ]) ->
Some(ident, isArray, [ singleChild ])
| App (OptVar (ident, _, _), [ (ArrayOrList (isArray, children, _) as aolEx) ])
| App (OptVar (ident, _, _), [ (ArrayOrListOfSeqExpr (isArray, CompExpr (_, Sequentials children)) as aolEx) ]) ->
Some(ident, isArray, children, aolEx.Range)
| App (OptVar (ident, _, _), [ (ArrayOrListOfSeqExpr (isArray, CompExpr (_, singleChild)) as aolEx) ]) ->
Some(ident, isArray, [ singleChild ], aolEx.Range)
| _ -> None

let (|ElmishReactWithChildren|_|) e =
Expand Down
9 changes: 9 additions & 0 deletions src/Fantomas/TriviaHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ module internal TriviaHelpers =
|> Option.map (fun t -> t.ContentAfter |> List.exists contentAfter)
|> Option.defaultValue false

let ``has content before that matches``
(findTrivia: TriviaNode -> bool)
(contentBefore: TriviaContent -> bool)
(trivia: TriviaNode list)
=
List.tryFind findTrivia trivia
|> Option.map (fun t -> t.ContentBefore |> List.exists contentBefore)
|> Option.defaultValue false

let ``has single line comment before`` (triviaNode: TriviaNode) =
triviaNode.ContentBefore
|> List.exists
Expand Down

0 comments on commit 20a09de

Please sign in to comment.