GitHub

September 1st Release

Pre-release

8.0.0-beta-001

Changed

  • =, >, <, % and %% cannot start a line at the column of their left-hand side: there the parser reads =, > and < as the = of a binding, and reads % and %% inside a quotation as a splice. Fantomas already kept them off that column, but did so with the layout that keeps the right-hand side beside the operator whenever it is short enough to fit, which needs the page width and a column count to predict and moves a 0 around when an unrelated part of the line changes length. It now follows the rule proposed in fsharp/fslang-design#836: the expression fits on one line, or it does not and the operator stays with the left-hand side while the right-hand side moves one level in, or the left-hand side itself spans several lines, in which case the operator and the right-hand side each take a line of their own. fsharp_multiline_bracket_style = stroustrup still overrides this for a right-hand side that opens a bracket, which keeps hugging the operator. This is the first beta of 8.0.0: the style guide for this is not settled yet, so give it a try and report back on the design issue if something reads worse than what it replaces. #3434

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-beta-001

August 29th Release

Pre-release

8.0.0-alpha-026

Changed

  • fsharp_multiline_bracket_style = stroustrup now applies to object expressions, so { stays on the line that opens the binding and new T with moves below it. Up to now object expressions were printed by the aligned branch whatever the setting said, which left { new T with on one line and made stroustrup the only bracket style that did not reach every bracket it names. The Microsoft style guide writes the form out under "Formatting object expressions" and Fantomas now produces it character for character. This was left alone in the belief that the layout was an offside error waiting to happen; it is not, and the compiler accepts it in a binding, a list item, a function argument, a lambda body, a match clause and a nested let alike. An object expression under stroustrup now lands where a record already landed in each of those positions. aligned, which is the default since 8.0.0-alpha-002, and cramped are untouched. #2990
  • fsharp_multiline_bracket_style = stroustrup now survives a binding whose signature broke across lines, and a match clause under fsharp_experimental_keep_indent_in_branch. Both were printed by branches written before stroustrup existed and never given a stroustrup-aware counterpart, so the setting was quietly overruled in each: a let whose parameters wrapped left its = alone on a line and indented the bracket below it, and a match clause under keep-indent did the same below the arrow. They now read = { and | _ -> {, with the items one level in and the closing bracket back at the column the binding or the clause started from, which is what the same code already produced when the signature fitted on one line or the setting was off. This reaches every bracket the setting names, so records, update records, anonymous records, anonymous structs, lists and arrays move with the object expressions of the entry above rather than behind them. The closing bracket of a match clause stays two columns right of the bar, because on the bar's own column the | of the next clause no longer parses. #3450

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-026

August 28th Release

Pre-release

8.0.0-alpha-025

Fixed

  • A ! line of a .fantomasignore takes a path back out again even when a line above it matched the folder holding that path, so sub/* followed by !sub/keep formats and checks the files under sub/keep. Since 8.0.0-alpha-016 a folder an ignore file names is never opened, which is what a folder pattern should mean and is not what it can mean here: closing sub decides that sub/keep is not there, and the line that would have taken it back out is never reached. The files were not reported as ignored, they were never found, so --check passed over a scope smaller than the ignore file describes and doctor, which asks about one file and answers correctly, disagreed with the run about that same file. An ignore file that negates anything now leaves every folder open and asks about the files inside one at a time, which is what every version up to 8.0.0-alpha-015 did. An ignore file with no ! line in it still closes the folders it names. #3447

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-025

August 28th Release

Pre-release

8.0.0-alpha-024

Fixed

  • The dots of a chain that breaks are indented past the head of the chain, instead of landing on the head's own column or to the left of it. A dot on the head's column reads as a new item rather than as the chain continuing, and inside a parenthesis the parser refuses the output outright: let v = ((someObject.First(a).Second(b).Third(c))) at two-space indentation produced code Fantomas would not accept from itself, so the file was left unformatted with a bug report on the console. The dots now step one indent level at a time until they clear the head, which keeps every column a multiple of the indent size; a chain whose dots already cleared its head is untouched. This replaces a branch that anchored a parenthesised chain on its opening parenthesis, written when only a real dot chain reached it. Since 8.0.0-alpha-014 a dotted long identifier is a chain too, so it also fired for the likes of Seq.map, which never breaks, and moved a lambda written behind such a call three columns for no reason. #3445

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-024

August 28th Release

Pre-release

8.0.0-alpha-023

Fixed

  • An operator that starts with a star keeps a space on either side of it inside the parentheses wherever its name is written, so val inline ( *. ): ... and abstract member ( *. ): ... survive formatting. Only let ( *. ) a b = ... was spaced before; a val in a signature file and an abstract member in either kind of file came out as (*.), which opens a block comment and swallows the rest of the file. Multiplication is unaffected, because (*) is a token the lexer knows. #3443

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-023

August 27th Release

Pre-release

8.0.0-alpha-022

Added

  • Extension members on tuple types, type (int * int) with ... and type struct (int * int) with ..., format instead of failing. The parser accepts them since dotnet/fsharp#19602, and a type definition's name is now any type in the Oak tree rather than only an identifier. The tuple prints as written; no layout decision was added for it. #3436

Changed

  • Update FCS to 'Rotate [<return: X>] attributes during binding normalization', commit 74ec4f7df70717a162d6ffd23007603cf298fb8b #3436

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-022

August 27th Release

Pre-release

8.0.0-alpha-021

Fixed

  • A call in the middle of a chain keeps its parenthesis against the member name when its lambda argument no longer fits, and breaks behind it instead. Up to now the whole argument moved down a line, ( and all, which is what the last call of a chain does, but for an earlier one it changes what the code means: a.Foo (x).Bar() passes (x).Bar() to Foo rather than calling Bar on the result. With a call behind it the compiler rejected the result with "This argument expression needs parentheses"; with a plain member behind it, such as .Value, nothing warned at all and the member quietly became part of the argument. Hanging the parameters under (fun would keep the parenthesis in place too, and the F# style guide rules that out, because the column they hang from is the length of the member name. The closing ) answers to fsharp_multi_line_lambda_closing_newline as it did before, and the last call of a chain is untouched, since nothing follows it to be swallowed. #3432

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-021

August 27th Release

Pre-release

8.0.0-alpha-020

Fixed

  • A list or an array on the right of =, >, <, % or %% is indented from the binding again, so let a = b = [ ... ] breaks to b = [ with its items one level in and the ] back at the column of b. Since 8.0.0-alpha-003 both the items and the closing bracket sat a further level to the right. The right-hand side of these operators is indented so that a comment between the operator and that side lands below the operator, which is what #2944 asked for, and so that the lines under a chain or an application are not read as a continuation of the left-hand side. A list or an array needs neither: its bracket says where the right-hand side begins and indents its items from the left-hand side by itself, so indenting it again pushed the items and the closing bracket a level too far. This concerns aligned, which is the default, and stroustrup. cramped lines the items up under the opening bracket, so the indent never reached them and nothing changes there. Right-hand sides that open a bracket in some other way, such as seq { }, <@ @>, begin ... end and new T(...), still carry the extra level; where a no-break operator should put what follows it is a wider question than this fix. #3428

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-020

August 26th Release

Pre-release

8.0.0-alpha-019

Fixed

  • A call on a constant receiver keeps its parenthesis tight, so "yow".Substring (0, 3) and 3L.ToString () come out as "yow".Substring(0, 3) and 3L.ToString(). 8.0.0-alpha-018 gave a constant receiver a space it was never meant to have. The rule there says a call keeps the space only when the whole thing being called is a plain dotted name, and the comment agreed at fslang-design#648 lists "yow".Substring(0, 3) under "a receiver that is not a name", beside (f x) and [ 1; 2 ]. The alpha carved constants back out on the reasoning that a constant is atomic rather than bracketed, which went past what was agreed and was not deliberate. A constant is a value, the rule asks for a name, so it goes tight. A type parameter really is a name, so 'T.set_StaticProperty (3) is unaffected. #3426

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-019

August 26th Release

Pre-release

8.0.0-alpha-018

Added

  • doctor names the .fantomasignore above the one that governs a file, when a pattern in it would have skipped that file. Fantomas reads the nearest ignore file at or above a file and no other, so a pattern written at the root of a repository has no effect on a folder that has an ignore file of its own beside it. Up to now the report named the ignore file that did decide and said nothing about the one that did not, which answers "which file" and leaves "then why did mine not" for the reader to work out. It quotes the pattern that would have matched, with its line number, the way it already quotes the line that decided. --json carries every ignore file above the governing one under shadowed, each with wouldIgnore and the lines of it that match, whether or not it would have decided anything. #3423

Changed

  • The settings that ask for a space before the parenthesis of a call, fsharp_space_before_uppercase_invocation and fsharp_space_before_lowercase_invocation, now get a say only when the whole thing being called is a plain dotted name. Put a call, an index, a bracketed receiver, or a type application anywhere in it, and the parenthesis stays tight whatever the settings ask for. On default settings xs.map(fun a -> a + 1).filter (fun a -> a > 1) becomes xs.map(fun a -> a + 1).filter(fun a -> a > 1), which is the report this started from, and Foo().bar () and myList.[7].someFunction (arg) lose their space for the same reason. A plain dotted name is untouched however long it gets, so List.map (f) and Fantomas.FCS.Text.Range.unionRanges (r1, r2) keep the space they had, and so is a literal or type parameter receiver, since "yow".Substring (0, 3) and 'T.set_StaticProperty (3) are atomic rather than bracketed. Agreed at fslang-design#648 and written up under Formatting chain expressions. #3425
  • A type application now makes a call tight with no chain in sight, which is the part of the change above most likely to catch you out, because it reaches ordinary generic calls rather than fluent code. On default settings unbox<bool> (value), f<int> (x), List.map<int> (f) and jsOptions<Vis.Options> (fun o -> ...) all lose their space, since fsharp_space_before_lowercase_invocation is true and each of those is a lower-case name carrying type arguments. An upper-case generic call such as Dictionary<string, int>(x) was already tight by default and only moves if fsharp_space_before_uppercase_invocation is on. Fantomas does not add parentheses, so the far more common form without them, unbox<int> obj, is left exactly as written and never comes into it. #3425

Fixed

  • More expression forms count as open-ended, so a record, list, array or tuple that holds one of them in a non-last position stays multiline instead of collapsing onto a line that means something else. #3279 settled fun, if, match and try, and left the forms that wrap one of those or end in one: lazy, yield, return, do, assert and fixed, an assignment such as x.P <- fun y -> y, and let x = 1 in body. { A = 1; B = lazy fun x -> x; C = 3 } reads back as a lambda that swallowed C = 3. A wrapper around something that closes on its own, lazy a or x.P <- 1, collapses as it always did. When this happens, why, and how to get the single line back is written up under Open-ended expressions. #3424

Special thanks to @nojaf!

https://www.nuget.org/packages/fantomas/8.0.0-alpha-018

Read the original on github.com ↗