diff --git a/src/Fantomas.Tests/FunctionDefinitionTests.fs b/src/Fantomas.Tests/FunctionDefinitionTests.fs index cd3e371cd6..ce689278c9 100644 --- a/src/Fantomas.Tests/FunctionDefinitionTests.fs +++ b/src/Fantomas.Tests/FunctionDefinitionTests.fs @@ -542,4 +542,33 @@ let private addTaskToScheduler .Build() 1 +""" + +[] +let ``long function signature should align with equal sign, 883`` () = + formatSourceString false """let readModel (updateState : 'State -> EventEnvelope<'Event> list -> 'State) (initState : 'State) : ReadModel<'Event, 'State> = + () +""" { config with IndentSpaceNum = 2; SpaceBeforeColon = true } + |> prepend newline + |> should equal """ +let readModel + (updateState : 'State -> EventEnvelope<'Event> list -> 'State) + (initState : 'State) + : ReadModel<'Event, 'State> + = + () +""" + +[] +let ``long function signature should align with equal sign, no return type`` () = + formatSourceString false """let readModel (updateState : 'State -> EventEnvelope<'Event> list -> 'State) (initState : 'State) = + () +""" { config with IndentSpaceNum = 2; SpaceBeforeColon = true; PageWidth = 80 } + |> prepend newline + |> should equal """ +let readModel + (updateState : 'State -> EventEnvelope<'Event> list -> 'State) + (initState : 'State) + = + () """ \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index fd02e2d39c..7c6719ae9f 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -544,6 +544,7 @@ and genLetBinding astContext pref b = ifElse astContext.IsFirstChild (genAttributes astContext ats -- pref) (!- pref +> genOnelinerAttributes astContext ats) + let afterLetKeyword = opt sepSpace ao genAccess +> ifElse isMutable (!- "mutable ") sepNone @@ -2748,10 +2749,10 @@ and genPatWithReturnType ao s ps tpso (t:SynType option) (astContext: ASTContext let hasBracket = ps |> Seq.map fst |> Seq.exists Option.isSome let genName = aoc -- s +> tpsoc +> sepSpace + let genParametersInitial = colAutoNlnSkip0 (ifElse hasBracket sepSemi sepSpace) ps (genPatWithIdent astContext) - let genReturnType, newlineBeforeReturnType = match t with | Some t -> genType astContext false t, sepNln @@ -2760,17 +2761,32 @@ and genPatWithReturnType ao s ps tpso (t:SynType option) (astContext: ASTContext let genParametersWithNewlines = (sepNln +> col sepNln ps (genPatWithIdent astContext) +> newlineBeforeReturnType) - let isLongFunctionSignature ctx= - futureNlnCheck (genName +> genParametersInitial +> genReturnType) ctx + let isLongFunctionSignature (ctx: Context) = + let space = 1 + let colon = if ctx.Config.SpaceBeforeColon then 3 else 2 + let lengthByAST = + getSynAccessLength ao + + lengthWhenSome (fun _ -> space) ao + + s.Length + + space + + List.sumBy (snd >> getSynPatLength >> (+) space) ps + + lengthWhenSome (fun _ -> colon) t + + lengthWhenSome getSynTypeLength t + + (ctx.Column + lengthByAST > ctx.Config.PageWidth) + || futureNlnCheck (genName +> genParametersInitial +> genReturnType) ctx - atCurrentColumn (fun ctx -> + fun ctx -> let isLong = isLongFunctionSignature ctx + let expr = genName +> ifElse hasBracket sepOpenT sepNone - +> ifElse isLong genParametersWithNewlines genParametersInitial + +> ifElse isLong (indent +> genParametersWithNewlines +> unindent) genParametersInitial +> ifElse hasBracket sepCloseT sepNone - expr ctx) + + expr ctx + and genConst (c:SynConst) (r:range) = match c with | SynConst.Unit -> diff --git a/src/Fantomas/SourceTransformer.fs b/src/Fantomas/SourceTransformer.fs index e23c38d9b3..7f4eeed6f7 100644 --- a/src/Fantomas/SourceTransformer.fs +++ b/src/Fantomas/SourceTransformer.fs @@ -1,5 +1,6 @@ module internal Fantomas.SourceTransformer +open FSharp.Compiler.SyntaxTree open Fantomas.Context open Fantomas.SourceParser @@ -128,4 +129,47 @@ let addParenForTupleWhen f synExpr ctx = | FSharp.Compiler.SyntaxTree.SynExpr.Lambda _ -> true |_ -> false // "if .. then .. else" have precedence over "," let expr = f synExpr - ifElse (condition synExpr) (sepOpenT +> expr +> sepCloseT) expr ctx \ No newline at end of file + ifElse (condition synExpr) (sepOpenT +> expr +> sepCloseT) expr ctx + +let lengthWhenSome f o = + match o with + | Some x -> f x + | None -> 0 + +let getSynAccessLength ao = + lengthWhenSome (function | SynAccess.Internal -> 8 | SynAccess.Private -> 7 | SynAccess.Public -> 6) ao + +let rec getSynTypeLength (synType: SynType) = + match synType with + | TFun (t1, t2) -> + getSynTypeLength t1 + (* -> *) 2 + getSynTypeLength t2 + | TVar(Typar(id, _)) -> + id.Length + | TApp(t, ts, _) -> + getSynTypeLength t + List.sumBy getSynTypeLength ts + | TLongIdent s -> + s.Length + | _ -> + 0 + +let rec getSynPatLength (synPat: SynPat) = + match synPat with + | PatLongIdent(ao, s, ps, _) -> + let accessLength = getSynAccessLength ao + let patternLength = + ps + |> List.sumBy (fun (ident, pat) -> + let identLength = lengthWhenSome String.length ident + identLength + getSynPatLength pat) + accessLength + patternLength + s.Length + + | PatParen pat -> 2 + getSynPatLength pat + + | PatNamed(ao,p,s) -> + let accessLength = getSynAccessLength ao + accessLength + getSynPatLength p + s.Length + + | PatTyped (p,t) -> + getSynPatLength p + getSynTypeLength t + + | _ -> 0 \ No newline at end of file