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

Ensure parenthesis around multiline expression before dot - fix #246 #314

Merged
merged 6 commits into from
Oct 1, 2018
Merged
Show file tree
Hide file tree
Changes from 5 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
39 changes: 39 additions & 0 deletions src/Fantomas.Tests/ClassTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,43 @@ let ``class inherit and augmentation``() =
with
let hello = "Hello"
member this.X = "Member"
"""

[<Test>]
let ``property long line``() =
formatSourceString false """type T() =
member __.Property = "hello"
let longNamedFunlongNamedFunlongNamedFunlongNamedFunlongNamedFun (x:T) = x
let longNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClass = T()

System.String.Concat("a", "b" +
longNamedFunlongNamedFunlongNamedFunlongNamedFunlongNamedFun(longNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClass).Property)
""" config
|> should equal """type T() =
member __.Property = "hello"

let longNamedFunlongNamedFunlongNamedFunlongNamedFunlongNamedFun (x : T) = x
let longNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClass =
T()

System.String.Concat
("a",
"b"
+ (longNamedFunlongNamedFunlongNamedFunlongNamedFunlongNamedFun
(longNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClasslongNamedClass)).Property)
"""

[<Test>]
let ``indexed get long line``() =
formatSourceString false """open System
type Exception with
member inline __.FirstLine =
__.Message.Split([|Environment.NewLine|], StringSplitOptions.RemoveEmptyEntries).[0]
""" config
|> should equal """open System

type Exception with
member inline __.FirstLine =
(__.Message.Split
([| Environment.NewLine |], StringSplitOptions.RemoveEmptyEntries)).[0]
"""
9 changes: 5 additions & 4 deletions src/Fantomas/CodePrinter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -643,11 +643,12 @@ and genExpr astContext = function
// At this stage, all symbolic operators have been handled.
| OptVar(s, isOpt) -> ifElse isOpt (!- "?") sepNone -- s
| LongIdentSet(s, e) -> !- (sprintf "%s <- " s) +> genExpr astContext e
| DotIndexedGet(e, es) -> genExpr astContext e -- "." +> sepOpenLFixed +> genIndexers astContext es +> sepCloseLFixed
| DotIndexedSet(e1, es, e2) -> genExpr astContext e1 -- ".[" +> genIndexers astContext es -- "] <- " +> genExpr astContext e2
| DotIndexedGet(e, es) -> addParenIfAutoNln e (genExpr astContext) -- "." +> sepOpenLFixed +> genIndexers astContext es +> sepCloseLFixed
| DotIndexedSet(e1, es, e2) -> addParenIfAutoNln e1 (genExpr astContext) -- ".[" +> genIndexers astContext es -- "] <- " +> genExpr astContext e2
| DotGet(e, s) ->
genExpr { astContext with IsInsideDotGet = true } e -- sprintf ".%s" s
| DotSet(e1, s, e2) -> genExpr astContext e1 -- sprintf ".%s <- " s +> genExpr astContext e2
let exprF = genExpr { astContext with IsInsideDotGet = true }
addParenIfAutoNln e exprF -- (sprintf ".%s" s)
| DotSet(e1, s, e2) -> addParenIfAutoNln e1 (genExpr astContext) -- sprintf ".%s <- " s +> genExpr astContext e2
| LetOrUseBang(isUse, p, e1, e2) ->
atCurrentColumn (ifElse isUse (!- "use! ") (!- "let! ")
+> genPat astContext p -- " = " +> genExpr astContext e1 +> sepNln +> genExpr astContext e2)
Expand Down
13 changes: 8 additions & 5 deletions src/Fantomas/FormatConfig.fs
Original file line number Diff line number Diff line change
Expand Up @@ -348,16 +348,19 @@ let internal sepOpenT = !- "("
/// closing token of tuple
let internal sepCloseT = !- ")"


/// Set a checkpoint to break at an appropriate column
let internal autoNlnOrAddSep f sep (ctx : Context) =
if not ctx.BreakLines then f (sep ctx) else
let internal autoNlnCheck f sep (ctx : Context) =
if not ctx.BreakLines then false else
// Create a dummy context to evaluate length of current operation
use colWriter = new ColumnIndentedTextWriter(new StringWriter())
let dummyCtx = ctx.With(colWriter)
let col = (dummyCtx |> sep |> f).Writer.Column
// This isn't accurate if we go to new lines
if col > ctx.Config.PageWidth then
col > ctx.Config.PageWidth

/// Set a checkpoint to break at an appropriate column
let internal autoNlnOrAddSep f sep (ctx : Context) =
let isNln = autoNlnCheck f sep ctx
if isNln then
f (sepNln ctx)
else
f (sep ctx)
Expand Down
6 changes: 5 additions & 1 deletion src/Fantomas/SourceTransformer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,8 @@ let rec (|OneLinerLetOrUseL|_|) = function
let rec (|MultilineLetOrUseL|_|) = function
| (prefix, MultilineBinding x)::MultilineLetOrUseL(xs, ys) -> Some((prefix, x)::xs, ys)
| (prefix, MultilineBinding x)::ys -> Some([prefix, x], ys)
| _ -> None
| _ -> None

let addParenIfAutoNln synExpr f ctx =
let expr = f synExpr
ifElse (autoNlnCheck expr sepNone ctx && not (hasParenthesis synExpr)) (sepOpenT +> expr +> sepCloseT) expr ctx