diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 0d0ca44b42..f1077c113e 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -465,20 +465,25 @@ let private findEmptyNewlinesInTokens (tokens: Token list) (lineCount) (ignoreRa |> Option.map (fun t -> t.LineNumber) |> Option.defaultValue lineCount + let ignoredLines = + ignoreRanges + |> List.collect(fun r -> [r.StartLine..r.EndLine]) + + let linesWithTokens = + tokens + |> List.groupBy (fun t -> t.LineNumber) + let completeEmptyLines = [1 .. lastLineWithContent] - |> List.filter (fun line -> - not (List.exists (fun t -> t.LineNumber = line) tokens) - && not (List.exists (fun (br:FSharp.Compiler.Range.range) -> br.StartLine < line && br.EndLine > line) ignoreRanges) - ) + |> List.except (ignoredLines @ List.map fst linesWithTokens) + |> List.filter (fun line -> not (List.exists (fun t -> t.LineNumber = line) tokens)) |> List.map createNewLine let linesWithOnlySpaces = - tokens - |> List.groupBy (fun t -> t.LineNumber) + linesWithTokens |> List.filter (fun (ln, g) -> ln <= lastLineWithContent && (List.length g) = 1 && (List.head g).TokenInfo.TokenName = "WHITESPACE") |> List.map (fst >> createNewLine) - + completeEmptyLines @ linesWithOnlySpaces let getTriviaFromTokens (tokens: Token list) linesCount = diff --git a/src/Fantomas/Trivia.fs b/src/Fantomas/Trivia.fs index ecc3ef5da7..8f2ae73e36 100644 --- a/src/Fantomas/Trivia.fs +++ b/src/Fantomas/Trivia.fs @@ -43,7 +43,7 @@ let private findFirstNodeOnLine (nodes: TriviaNode list) lineNumber : TriviaNode |> List.filter (fun { Range =r } -> r.StartLine = lineNumber) |> List.tryHead -let private mainNodeIs name (t:TriviaNodeAssigner) = +let inline private mainNodeIs name (t:TriviaNodeAssigner) = match t.Type with | MainNode(mn) -> mn = name | _ -> false @@ -54,7 +54,7 @@ let private nodesContainsBothAnonModuleAndOpen (nodes: TriviaNodeAssigner list) // the member keyword is not part of an AST node range // so it is not an ideal candidate node to have trivia content -let private isNotMemberKeyword (node: TriviaNodeAssigner) = +let inline private isNotMemberKeyword (node: TriviaNodeAssigner) = match node.Type with | Token({ TokenInfo = ti }) when (ti.TokenName = "MEMBER") -> false | _ -> true @@ -232,7 +232,7 @@ let private findASTNodeOfTypeThatContains (nodes: TriviaNodeAssigner list) typeN | _ -> false) |> List.tryHead -let private addTriviaToTriviaNode (startOfSourceCode:int) (triviaNodes: TriviaNodeAssigner list) trivia = +let private addTriviaToTriviaNode triviaBetweenAttributeAndParentBinding (startOfSourceCode:int) (triviaNodes: TriviaNodeAssigner list) trivia = match trivia with | { Item = Comment(LineCommentOnSingleLine(_)) as comment; Range = range } when (commentIsAfterLastTriviaNode triviaNodes range) -> // Comment on is on its own line after all Trivia nodes, most likely at the end of a module @@ -381,8 +381,10 @@ let collectTrivia tokens lineCount (ast: ParsedInput) = let triviaNodesFromAST = flattenNodeToList node |> filterNodes - |> List.map mapNodeToTriviaNode - |> List.choose id + |> List.choose mapNodeToTriviaNode + + let hasAnyAttributes = List.exists (fun (tn:TriviaNodeAssigner) -> match tn.Type with | MainNode("SynAttributeList") -> true | _ -> false) triviaNodesFromAST + let triviaBetweenAttributeAndParentBinding = if hasAnyAttributes then triviaBetweenAttributeAndParentBinding else (fun _ _ -> None) let triviaNodesFromTokens = TokenParser.getTriviaNodesFromTokens tokens let triviaNodes = triviaNodesFromAST @ triviaNodesFromTokens |> List.sortBy (fun n -> n.Range.Start.Line, n.Range.Start.Column) @@ -391,7 +393,7 @@ let collectTrivia tokens lineCount (ast: ParsedInput) = match trivias with | [] -> [] | _ -> - List.fold (addTriviaToTriviaNode startOfSourceCode) triviaNodes trivias + List.fold (addTriviaToTriviaNode triviaBetweenAttributeAndParentBinding startOfSourceCode) triviaNodes trivias |> List.choose (fun tn -> if triviaNodeIsNotEmpty tn then { Type = tn.Type