diff --git a/build.fsx b/build.fsx index 32366c382f..3e251f3ab4 100644 --- a/build.fsx +++ b/build.fsx @@ -340,7 +340,7 @@ Target.create "Docs" (fun _ -> DotNet.exec id "fsdocs" - $"build --clean --properties Configuration=Release --fscoptions \" -r:{semanticVersioning}\"" + $"build --clean --properties Configuration=Release --fscoptions \" -r:{semanticVersioning}\" --eval" |> ignore) // -------------------------------------------------------------------------------------- diff --git a/docs/.README.md b/docs/.README.md index fd7638fc8b..0abc5e1b66 100644 --- a/docs/.README.md +++ b/docs/.README.md @@ -2,7 +2,7 @@ To run the website: -> dotnet fsdocs watch +> dotnet fsdocs watch --eval To compile the Sass: @@ -16,4 +16,4 @@ To build the website: > dotnet fsi .\docs\\.style\style.fsx -> dotnet fsdocs build +> dotnet fsdocs build --eval diff --git a/docs/.style/fsdocs-custom.sass b/docs/.style/fsdocs-custom.sass index 6803bf2caf..7df79c2609 100644 --- a/docs/.style/fsdocs-custom.sass +++ b/docs/.style/fsdocs-custom.sass @@ -41,6 +41,11 @@ $headings-font-family: 'Reem Kufi', sans-serif #fsdocs-content box-shadow: 0 4px 10px $drop-shadow + table.pre + background-color: $pearl + pre + background-color: $pearl + color: $primary h1, h2, h3, h4, h5, h6 a color: $black @@ -64,6 +69,16 @@ $headings-font-family: 'Reem Kufi', sans-serif font-size: 1.2rem padding: 15px 0 10px 0 font-weight: 400 + h4 + .green-recommendation, .orange-recommendation, .red-recommendation + vertical-align: 0 + margin-right: 0.5rem + font-size: 1.3rem + .gresearch-recommendation + vertical-align: -0.2rem + margin-right: 0.5rem + width: 20px + height: 20px hr margin: 0 0 20px 0 li @@ -92,6 +107,35 @@ $headings-font-family: 'Reem Kufi', sans-serif line-height: 1 color: $white + .green-recommendation + color: $success + vertical-align: middle + font-size: 1.4rem + .red-recommendation + color: $danger + vertical-align: middle + font-size: 1.4rem + .orange-recommendation + color: $warning + vertical-align: middle + font-size: 1.4rem + .gresearch-recommendation + padding: 3px + background-color: $gresearch-color + border-radius: 50% + +.green-tooltip + .tooltip-inner + background-color: $success +.red-tooltip + .tooltip-inner + background-color: $danger +.orange-tooltip + .tooltip-inner + background-color: $warning +.gresearch-tooltip + .tooltip-inner + background-color: $gresearch-color .fsdocs-source-link float: right text-decoration: none diff --git a/docs/.style/variables.sass b/docs/.style/variables.sass index 30c73d6d7f..e6f0b6b763 100644 --- a/docs/.style/variables.sass +++ b/docs/.style/variables.sass @@ -5,9 +5,13 @@ $drop-shadow: rgba(22, 22, 22, 0.2) $white: #FFF $pearl: #f6f7f7 $menu-open: #347193 +$success: #92DC84 +$warning: #F5BF4F +$danger: #EA7268 +$gresearch-color: #00A8E2 $navbar-light-brand-color: $white $navbar-light-brand-hover-color: $white $navbar-light-color: $white $navbar-light-active-color: $secondary $navbar-light-hover-color: $white -$navbar-nav-link-padding-x: 0 \ No newline at end of file +$navbar-nav-link-padding-x: 0 diff --git a/docs/_template.html b/docs/_template.html index ab8b9e0281..2b2dbc299d 100644 --- a/docs/_template.html +++ b/docs/_template.html @@ -1,5 +1,5 @@  - + @@ -23,7 +23,6 @@
- -
+ - diff --git a/docs/content/fantomas-setting-icon.js b/docs/content/fantomas-setting-icon.js new file mode 100644 index 0000000000..d0c31c710c --- /dev/null +++ b/docs/content/fantomas-setting-icon.js @@ -0,0 +1,35 @@ +import { html } from 'https://cdn.skypack.dev/lit'; +import { component } from 'https://cdn.skypack.dev/haunted'; + + +function FantomasSettingIcon({ tooltip, type }) { + let settingType + switch (type) { + case 'green': + settingType = {icon: "bi-check-circle-fill", color: "green-recommendation", tooltip: tooltip?tooltip:"This setting is good to use"} + break; + case 'orange': + settingType = {icon:"bi-exclamation-circle-fill", color:"orange-recommendation", tooltip: tooltip?tooltip:"This setting is not recommended"} + break; + case 'red': + settingType = {icon: "bi-x-circle-fill", color:"red-recommendation", tooltip: tooltip?tooltip:"You shouldn't use this setting"} + break; + } + return html``; +} + +function FantomasSettingIconGResearch({ tooltip }) { + const root = document.documentElement.dataset.root + const safeTooltip = + tooltip ? tooltip : "If you use one of these you should use all G-Research settings for consistency reasons"; + + return html`G-Research logo`; +} + +customElements.define('fantomas-setting-icon', component(FantomasSettingIcon, { useShadowDOM: false, + observedAttributes: [ 'tooltip','type'] })); + +customElements.define('fantomas-setting-icon-gresearch', component(FantomasSettingIconGResearch, { useShadowDOM: false, + observedAttributes: [ 'tooltip'] })); \ No newline at end of file diff --git a/docs/docs/end-users/Configuration.fsx b/docs/docs/end-users/Configuration.fsx new file mode 100644 index 0000000000..9b59671eea --- /dev/null +++ b/docs/docs/end-users/Configuration.fsx @@ -0,0 +1,714 @@ +(** +--- +category: End-users +categoryindex: 1 +index: 3 +--- +*) + +(** +# Configuration +Fantomas ships with a limited series of options. +These can be stored in an [.editorconfig](https://editorconfig.org/) file and will be picked up automatically by the +commandline. +Your IDE should respect your settings, however the implementation of that is editor specific. Setting the configuration via +UI might be available depending on the IDE. +*) + +(** +## Usage +Inside .editorconfig you can specify the file extension and code location to be use per config: +``` +[*.fs] +fsharp_space_before_uppercase_invocation = true + +# Write a comment by starting the line with a '#' +[*.{fs,fsx,fsi}] +fsharp_bar_before_discriminated_union_declaration = true + +# Apply specific settings for a targeted subfolder +[src/Elmish/View.fs] +fsharp_multiline_block_brackets_on_same_column = true +fsharp_experimental_stroustrup_style = true +``` +*) + +(** +## Trying your settings via the online tool +You can quickly try your settings via the online tool. +drawing +*) + +#r "nuget: Fantomas.Core, 5.0.0-beta-*" + +open Fantomas.Core.FormatConfig +open Fantomas.Core +let formatCode input configIndent = + CodeFormatter.FormatDocumentAsync (false, input, configIndent) + |> Async.RunSynchronously + +(** +## Settings recommendations +Fantomas ships with a series of settings that you can use freely depending on your case. +However, there are settings that we do not recommend and generally should not be used. +

Safe to change: Settings that aren't attached to any guidelines. Depending on your team or your own preferences, feel free to change these as it's been agreed on the codebase, however, you can always use it's defaults.

+

Not recommended: Settings that don't follow any guidelines.

+

Do not use: Settings where it is not recommended to change the default value. They might lead to incomplete results.

+

G-Research: G-Research styling guide. If you use one of these, for consistency reasons you should use all of them.

+*) + +(** +## Auxiliary settings +Lorep ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisi vel consectetur interdum, nisi nisi consectetur nisl, eget consectetur nisl nisi vel nisi. +#### indent_size +` indent_size` has to be between 1 and 10. + +This preference sets the indentation +The common values are 2 and 4. +The same indentation is ensured to be consistent in a source file. +Default = 4. +*) + +formatCode + """ + let inline selectRandom (f: _ []) = + let r = random 1.0 + + let rec find = + function + | 0 -> fst f.[0] + | n when r < snd f.[n] -> fst f.[n] + | n -> find (n - 1) + + find <| f.Length - 1 + """ + { FormatConfig.Default with IndentSize = 2 } +(*** include-it ***) +(** +#### max_line_length +`max_line_length` has to be an integer greater or equal to 60. +This preference sets the column where we break F# constructs into new lines. +Default = 120. +*) + +formatCode + """ + match myValue with + | Some foo -> someLongFunctionNameThatWillTakeFooAndReturnsUnit foo + | None -> printfn "nothing" + """ + { FormatConfig.Default with MaxLineLength = 60 } +(*** include-it ***) + +(** +#### end_of_line +`end_of_line` determines the newline character, `lf` will add `\n` where `crlf` will add `\r\n`. +`cr` is not supported by the F# language spec. +If not set by the user, the default value is determined by `System.Environment.NewLine`. +*) + +(** +#### insert_final_newline +Adds a final newline character at the end of the file. +Default = true +*) + +formatCode + """ + let a = 42 + """ + { FormatConfig.Default with InsertFinalNewline = false } +(*** include-it ***) + +(** +#### fsharp_space_before_parameter +Add a space after the name of a function and before the opening parenthesis of the first parameter. +This setting influences function definitions. +Default = true. +*) + +formatCode + """ + let value (a: int) = x + let DumpTrace() = () + """ + { FormatConfig.Default with SpaceBeforeParameter = false } +(*** include-it ***) + +(** +#### fsharp_space_before_lowercase_invocation +Add a space after the name of a lowercased function and before the opening parenthesis of the first argument. +This setting influences function invocation. +Default = true. +*) + +formatCode + """ + value (a, b) + startTimer () + """ + { FormatConfig.Default with SpaceBeforeLowercaseInvocation = false } +(*** include-it ***) + +(** +#### fsharp_space_before_uppercase_invocation +Add a space after the name of a uppercased function and before the opening parenthesis of the first argument. +This setting influences function invocation. +Default = false. +*) + +formatCode + """ + Value(a, b) + person.ToString() + """ + { FormatConfig.Default with SpaceBeforeUppercaseInvocation = true } +(*** include-it ***) + +(** +#### fsharp_space_before_class_constructor +Add a space after a type name and before the class constructor. +Default = false. +*) + +formatCode + """ + type Person() = + class + end + """ + { FormatConfig.Default with SpaceBeforeClassConstructor = true } + +(*** include-it ***) + +(** +#### fsharp_space_before_member +Add a space after a member name and before the opening parenthesis of the first parameter. +Default = false. +*) + +formatCode + """ + type Person() = + member this.Walk(distance: int) = () + member this.Sleep() = ignore + member __.singAlong() = () + member __.swim(duration: TimeSpan) = () + """ + { FormatConfig.Default with SpaceBeforeMember = true } +(*** include-it ***) + +(** +#### fsharp_space_before_colon +Add a space before `:`. Please note that not every `:` is controlled by this setting. +Default = false +*) + +formatCode + """ + type Point = { x: int; y: int } + let myValue: int = 42 // See https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#right-pad-value-and-function-argument-type-annotations + let update (msg: Msg) (model: Model) : Model = model // See https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#surround-return-type-annotations-with-white-space + """ + { FormatConfig.Default with SpaceBeforeColon = true } +(*** include-it ***) + +(** +#### fsharp_space_after_comma +Adds a space after `,` in tuples. +Default = true. +*) + +formatCode + """ + myValue.SomeFunction(foo, bar, somethingElse) + (a, b, c) + """ + { FormatConfig.Default with SpaceAfterComma = false } +(*** include-it ***) + +(** +#### fsharp_space_before_semicolon +Adds a space before `;` in records, arrays, lists, etc. +Default = false. +*) + +formatCode + """ + let a = [ 1 ; 2 ; 3 ] + let b = [| foo ; bar |] + type C = { X: int ; Y: int } + """ + { FormatConfig.Default with SpaceBeforeSemicolon = true } +(*** include-it ***) + +(** +#### fsharp_space_after_semicolon +Adds a space after `;` in records, arrays, lists, etc. +Default = true. +*) + +formatCode + """ + let a = [ 1; 2; 3 ] + let b = [| foo; bar |] + type C = { X: int; Y: int } + """ + { FormatConfig.Default with SpaceAfterSemicolon = false } +(*** include-it ***) + +(** +#### fsharp_space_around_delimiter +Adds a space around delimiters like `[`,`[|`,{`. +Default = true. +*) + +formatCode + """ + let a = [ 1;2;3 ] + let b = [| 4;5;6 |] + """ + { FormatConfig.Default with SpaceAroundDelimiter = false } + (*** include-it ***) + + +(** +## Maximum width constraints +#### fsharp_max_if_then_short_width +Control the maximum length for which if/then expression without an else expression can be on one line. +The [Microsoft F# style guide](https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions) recommends to never write such an expression in one line. +> If the else expression is absent, it is recommended to never to write the entire expression in one line. +Default = 0. +*) + +formatCode + """ + if a then + () + """ + { FormatConfig.Default with MaxIfThenShortWidth = 15 } +(*** include-it ***) + +(** +#### fsharp_max_if_then_else_short_width +Fantomas by default follows the if/then/else conventions listed in the [Microsoft F# style guide](https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions). +There is stated: + +> Indentation of conditionals depends on the size and complexity of the expressions that make them up. Write them on one line when: +> cond, e1, and e2 are short +> e1 and e2 are not if/then/else expressions themselves +This setting facilitates this by determining the maximum character width where the if/then/else expression stays in one line. +Default = 40. +*) + +formatCode + """ + if myCheck then truth else bogus + """ + { FormatConfig.Default with MaxIfThenElseShortWidth = 10 } +(*** include-it ***) + +(** +#### fsharp_max_infix_operator_expression +Control the maximum length for which infix expression can be on one line. +Default = 50. +*) +formatCode + """ + let WebApp = + route "/ping" >=> authorized >=> text "pong" + """ + { FormatConfig.Default with MaxInfixOperatorExpression = 20 } +(*** include-it ***) + +(** +#### fsharp_max_record_width +Control the maximum width for which records should be in one line. +Default = 40. +Requires `fsharp_record_multiline_formatter` to be `character_width` to take effect. +*) + +formatCode + """ + type MyRecord = { X: int; Y: int; Length: int } + let myInstance = { X = 10; Y = 20; Length = 90 } + """ + { FormatConfig.Default with MaxRecordWidth = 20 } +(*** include-it ***) + +(** +#### fsharp_max_record_number_of_items +Control the maximum number of fields for which records should be in one line. +Default = 1. +Requires `fsharp_record_multiline_formatter` to be +`number_of_items` to take effect. +*) + +formatCode + """ + type R = { x: int } + + type S = { x: int; y: string } + + type T = { x: int; y: string; z: float } + + let myRecord = { r = 3 } + + let myRecord' = { r with x = 3 } + + let myRecord'' = { r with x = 3; y = "hello" } + + let myRecord''' = { r with x = 3; y = "hello"; z = 0.0 } + """ + { FormatConfig.Default with MaxRecordSize = 2; RecordMultilineFormatter = MultilineFormatterType.NumberOfItems } +(*** include-it ***) + +(** +#### fsharp_record_multiline_formatter +Split records expressions/statements into multiple lines based on the given condition. `character_width` uses character count of the expression, controlled +by `fsharp_max_record_width`. `number_of_items` uses the number of fields in the record, controlled by `fsharp_max_record_number_of_items`. +Default = `character_width`. Note that in either case, record expressions/statements are still governed by `max_line_length`. +*) + +formatCode + """ + type R = { x: int } + + type S = { x: int; y: string } + + let myRecord = { r = 3 } + + let myRecord' = { r with x = 3 } + + let myRecord'' = { r with x = 3; y = "hello" } + """ + { FormatConfig.Default with RecordMultilineFormatter = MultilineFormatterType.NumberOfItems } +(*** include-it ***) + +(** +#### fsharp_max_array_or_list_width +Control the maximum width for which lists and arrays can be in one line. Default= 40. Requires `fsharp_array_or_list_multiline_formatter` to be `character_width` to take effect +*) + +formatCode + """ + let myArray = [| one; two; three |] + """ + { FormatConfig.Default with MaxArrayOrListWidth = 20 } +(*** include-it ***) + +(** +#### fsharp_max_array_or_list_number_of_items +Control the maximum number of elements for which lists and arrays can be in one line. +Default = 1. +Requires `fsharp_array_or_list_multiline_formatter` to be `number_of_items` to take effect. +*) + +formatCode + """ + let myList = [ one; two ] + let myArray = [| one; two; three |] + """ + { FormatConfig.Default with MaxArrayOrListNumberOfItems = 2; ArrayOrListMultilineFormatter = MultilineFormatterType.NumberOfItems } +(*** include-it ***) + +(** +#### fsharp_array_or_list_multiline_formatter +Split arrays and lists into multiple lines based on the given condition. `character_width` uses character count of the expression, controlled by +`fsharp_max_array_or_list_width`. `number_of_items` uses the number of elements +in the array or list, controlled by `fsharp_max_array_or_list_number_of_items`. +Default = `character_width`. Note that in either case, list expressions are still governed by `max_line_length`. +*) + +formatCode + """ + let myArray = [| one; two; three |] + """ + { FormatConfig.Default with ArrayOrListMultilineFormatter = MultilineFormatterType.NumberOfItems } +(*** include-it ***) + +(** +#### fsharp_max_value_binding_width +Control the maximum expression width for which let and member value/property bindings should be in one line. +The width is that of the pattern for the binding plus the implementating expression but not the keywords (e.g. "let"). +Default = 80. +*) + +formatCode + """ + let title = "Great title of project" + type MyType() = + member this.HelpText = "Some help text" + """ + { FormatConfig.Default with MaxValueBindingWidth = 10 } +(*** include-it ***) + +(** +#### fsharp_max_function_binding_width +Control the maximum width for which function and member bindings should be in one line. +Default = 40 +*) + +formatCode + """ + let title = "Great title of project" + type MyType() = + member this.HelpText = "Some help text" + """ + { FormatConfig.Default with MaxFunctionBindingWidth = 10 } +(*** include-it ***) + +(** +#### fsharp_max_dot_get_expression_width +Control the maximum width for which (nested) [SynExpr.DotGet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#DotGet) expressions should be in one line. +Default = 50. +*) + +formatCode + """ + let job = + JobBuilder + .UsingJobData(jobDataMap) + .Create() + .Build() + """ + { FormatConfig.Default with MaxDotGetExpressionWidth = 100 } +(*** include-it ***) + +(** +## G-Research style +#### fsharp_multiline_block_brackets_on_same_column +Alternative way of formatting records, arrays and lists. This will align the braces at the same column level. +Default = false. +*) + +formatCode + """ + let myRecord = + { Level = 1 + Progress = "foo" + Bar = "bar" + Street = "Bakerstreet" + Number = 42 } + + type Range = + { From: float + To: float } + + let a = + [| (1, 2, 3) + (4, 5, 6) + (7, 8, 9) |] + """ + { FormatConfig.Default with MultilineBlockBracketsOnSameColumn = true } +(*** include-it ***) + +(** +#### fsharp_newline_between_type_definition_and_members +Adds a new line between a type definition and its first member. +Default = false. +*) + +formatCode + """ + type Range = + { From: float + To: float } + member this.Length = this.To - this.From + """ + { FormatConfig.Default with NewlineBetweenTypeDefinitionAndMembers = true } +(*** include-it ***) + +(** +#### fsharp_align_function_signature_to_indentation +When a function signature exceeds the `max_line_length`, Fantomas will put all parameters on separate lines. +This setting also places the equals sign and return type on a new line. +Default = false. +*) + +formatCode + """ + [] + let run + ([] req: HttpRequest) + (log: ILogger) + : HttpResponse = + Http.main CodeFormatter.GetVersion format FormatConfig.FormatConfig.Default log req + """ + { FormatConfig.Default with AlignFunctionSignatureToIndentation = true } +(*** include-it ***) + +(** +#### fsharp_alternative_long_member_definitions +Provides an alternative way of formatting long member and constructor definitions, +where the difference is mainly in the equal sign and returned type placement. +Default = false. +*) + +formatCode + """ + type C + ( + aVeryLongType: AVeryLongTypeThatYouNeedToUse, + aSecondVeryLongType: AVeryLongTypeThatYouNeedToUse, + aThirdVeryLongType: AVeryLongTypeThatYouNeedToUse + ) = + class + end + + type D() = + member _.LongMethodWithLotsOfParameters + ( + aVeryLongParam: AVeryLongTypeThatYouNeedToUse, + aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse, + aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse + ) : ReturnType = + 42 + """ + { FormatConfig.Default with AlternativeLongMemberDefinitions = true } +(*** include-it ***) + +(** +#### fsharp_multi_line_lambda_closing_newline +Places the closing parenthesis of a multiline lambda argument on the next line. +Default = false. +*) + +formatCode + """ + let printListWithOffset a list1 = + List.iter + (fun { ItemOne = a } -> + // print + printfn "%s" a) + list1 + + let printListWithOffset a list1 = + list1 + |> List.iter + (fun elem -> + // print stuff + printfn "%d" (a + elem)) + + """ + { FormatConfig.Default with AlternativeLongMemberDefinitions = true } +(*** include-it ***) + +(** +#### fsharp_experimental_keep_indent_in_branch +Breaks the normal indentation flow for the last branch of a pattern match or if/then/else expression. +Only when the pattern match or if/then/else is the return value of a function or member. + +*This feature is considered experimental and is subject to change* +*) + +formatCode + """ + let main argv = + let args = parse argv + + let instructions = Library.foo args + + if args.DryRun = RunMode.Dry then + printfn "Would execute actions, but --dry-run was supplied: %+A" instructions + 0 + else + // proceed with main method + let output = Library.execute instructions + // do more stuff + 0 + """ + { FormatConfig.Default with KeepIndentInBranch = true } +(*** include-it ***) + +(** +#### fsharp_blank_lines_around_nested_multiline_expressions +Surround **nested** multi-line expressions with blank lines. +Existing blank lines are always preserved (via trivia), with exception when [fsharp_keep_max_number_of_blank_lines](#fsharp_keep_max_number_of_blank_lines) is used. +Top level expressions will always follow the [2020 blank lines revision](https://github.com/fsprojects/fantomas/blob/master/docs/FormattingConventions.md#2020-revision) principle. +Default = true. +*) + +formatCode + """ + let topLevelFunction () = + printfn "Something to print" + + try + nothing () + with + | ex -> + splash () + () + + let secondTopLevelFunction () = + // ... + () + """ + { FormatConfig.Default with BlankLinesAroundNestedMultilineExpressions = false } +(*** include-it ***) + +(** +#### fsharp_bar_before_discriminated_union_declaration +Always use a `|` before every case in the declaration of a discriminated union. If `false`, a `|` character is used only in multiple-case discriminated unions, and is omitted in short single-case DUs. +Default = false. +*) + +formatCode + """ + type MyDU = Short of int + """ + { FormatConfig.Default with BarBeforeDiscriminatedUnionDeclaration = true } + +(*** include-it ***) + +(** +## Other +Lorep ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisi vel consectetur interdum, nisi nisi consectetur nisl, eget consectetur nisl nisi vel nisi. +#### fsharp_experimental_stroustrup_style +Please contribute to https://github.com/fsprojects/fantomas/issues/1408. +*) + +(** +#### fsharp_keep_max_number_of_blank_lines +Set maximal number of consecutive blank lines to keep from original source. It doesn't change number of new blank lines generated by Fantomas. +Default=100 +*) + +formatCode + """ + open Foo + + let x = 42 + """ + { FormatConfig.Default with KeepMaxNumberOfBlankLines = 1 } +(*** include-it ***) + + +(** +#### fsharp_strict_mode +If being set, pretty printing is only done via ASTs. Compiler directives, inline comments and block comments will be ignored. +There are numerous situations when the information in the AST alone cannot restore the original code. +**Please do not use this setting for formatting hand written code!** +Valid use-case of this settings is code generation in projects like [FsAst](https://github.com/ionide/FsAst) and [Myriad](https://github.com/MoiraeSoftware/myriad). +Default = false. +*) + +formatCode + """ + // some great comment + let add a b = + #if INTERACTIVE + 42 + #else + a + b + #endif + """ + { FormatConfig.Default with StrictMode = true } +(*** include-it ***) +(** +
+ Previous + Next +
+*) \ No newline at end of file diff --git a/docs/docs/end-users/Configuration.md b/docs/docs/end-users/Configuration.md deleted file mode 100644 index 73a2f1ca77..0000000000 --- a/docs/docs/end-users/Configuration.md +++ /dev/null @@ -1,1036 +0,0 @@ ---- -category: End-users -categoryindex: 1 -index: 3 ---- -# Configuration - -Fantomas ships with a series of format options. -These can be stored in an [.editorconfig](https://editorconfig.org/) file and will be picked up automatically by the commandline tool. - -A default .editorconfig file would look like -```ini -[*.{fs,fsx}] -indent_size=4 -max_line_length=120 -end_of_line=crlf -insert_final_newline=true -fsharp_space_before_parameter=true -fsharp_space_before_lowercase_invocation=true -fsharp_space_before_uppercase_invocation=false -fsharp_space_before_class_constructor=false -fsharp_space_before_member=false -fsharp_space_before_colon=false -fsharp_space_after_comma=true -fsharp_space_before_semicolon=false -fsharp_space_after_semicolon=true -fsharp_space_around_delimiter=true -fsharp_max_if_then_short_width=0 -fsharp_max_if_then_else_short_width=40 -fsharp_max_infix_operator_expression=50 -fsharp_max_record_width=40 -fsharp_max_record_number_of_items=1 -fsharp_record_multiline_formatter=character_width -fsharp_max_array_or_list_width=40 -fsharp_max_array_or_list_number_of_items=1 -fsharp_array_or_list_multiline_formatter=character_width -fsharp_max_value_binding_width=80 -fsharp_max_function_binding_width=40 -fsharp_max_dot_get_expression_width=50 -fsharp_multiline_block_brackets_on_same_column=false -fsharp_newline_between_type_definition_and_members=false -fsharp_align_function_signature_to_indentation=false -fsharp_alternative_long_member_definitions=false -fsharp_multi_line_lambda_closing_newline=false -fsharp_experimental_keep_indent_in_branch=false -fsharp_blank_lines_around_nested_multiline_expressions=true -fsharp_bar_before_discriminated_union_declaration=false -fsharp_experimental_stroustrup_style=false -fsharp_keep_max_number_of_blank_lines=100 -fsharp_strict_mode=false -``` - -Please note that you should only add settings to the `.editorconfig` file when you want to deviate from the default settings. -Copying the entire list above is unnecessary. - -### indent_size - -` indent_size` has to be between 1 and 10. - -This preference sets the indentation -The common values are 2 and 4. -The same indentation is ensured to be consistent in a source file. -Default = 4. - -`defaultConfig` - -```fsharp -let inline selectRandom (f: _ []) = - let r = random 1.0 - - let rec find = - function - | 0 -> fst f.[0] - | n when r < snd f.[n] -> fst f.[n] - | n -> find (n - 1) - - find <| f.Length - 1 -``` - -`{ defaultConfig with IdentSize = 2 }` - -```fsharp -let inline selectRandom (f: _ []) = - let r = random 1.0 - - let rec find = - function - | 0 -> fst f.[0] - | n when r < snd f.[n] -> fst f.[n] - | n -> find (n - 1) - - find <| f.Length - 1 -``` - -### max_line_length - -`max_line_length` has to be an integer greater or equal to 60. -This preference sets the column where we break F# constructs into new lines. -Default = 120. - -`defaultConfig` - -```fsharp -match myValue with -| Some foo -> someLongFunctionNameThatWillTakeFooAndReturnsUnit foo -| None -> printfn "nothing" -``` - -`{ defaultConfig with MaxLineLength = 60 }` - -```fsharp -match myValue with -| Some foo -> - someLongFunctionNameThatWillTakeFooAndReturnsUnit foo -| None -> printfn "nothing" -``` - -### end_of_line - -`end_of_line` determines the newline character, `lf` will add `\n` where `crlf` will add `\r\n`. -`cr` is not supported by the F# language spec. -If not set by the user, the default value is determined by `System.Environment.NewLine`. - -### insert_final_newline - -Adds a final newline character at the end of the file. -Default = true - -`defaultConfig` - -```fsharp -let a = 42 - -``` - -`{ default with InsertFinalNewline = false }` - -```fsharp -let a = 42 -``` - -### fsharp_space_before_parameter - -Add a space after the name of a function and before the opening parenthesis of the first parameter. -This setting influences function definitions. -Default = true. - -`defaultConfig` - -```fsharp -let value (a: int) = x -let DumpTrace () = () -``` - -`{ defaultConfig with SpaceBeforeParameter = false }` - -```fsharp -let value(a: int) = x -let DumpTrace() = () -``` - -### fsharp_space_before_lowercase_invocation - -Add a space after the name of a lowercased function and before the opening parenthesis of the first argument. -This setting influences function invocation. -Default = true. - -`defaultConfig` - -```fsharp -value (a, b) -startTimer () -``` - -`{ defaultConfig with SpaceBeforeLowercaseInvocation = false }` - -```fsharp -value(a, b) -startTimer() -``` - -### fsharp_space_before_uppercase_invocation - -Add a space after the name of a uppercased function and before the opening parenthesis of the first argument. -This setting influences function invocation. -Default = false. - -`defaultConfig` - -```fsharp -Value(a, b) -person.ToString() -``` - -`{ defaultConfig with SpaceBeforeUppercaseInvocation = true }` - -```fsharp -Value (a, b) -person.ToString () -``` - -### fsharp_space_before_class_constructor - -Add a space after a type name and before the class constructor. -Default = false. - -`defaultConfig` - -```fsharp -type Person() = - class - end -``` - -`{ defaultConfig with SpaceBeforeClassConstructor = true }` - -```fsharp -type Person () = - class - end -``` - -### fsharp_space_before_member - -Add a space after a member name and before the opening parenthesis of the first parameter. -Default = false. - -`defaultConfig` - -```fsharp -type Person() = - member this.Walk(distance: int) = () - member this.Sleep() = ignore - member __.singAlong() = () - member __.swim(duration: TimeSpan) = () -``` - -`{ defaultConfig with SpaceBeforeMember = true }` - -```fsharp -type Person() = - member this.Walk (distance: int) = () - member this.Sleep () = ignore - member __.singAlong () = () - member __.swim (duration: TimeSpan) = () -``` - -### fsharp_space_before_colon - -Add a space before `:`. Please note that not every `:` is controlled by this setting. -Default = false. - -`defaultConfig` - -```fsharp -type Point = { x: int; y: int } -let myValue: int = 42 // See https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#right-pad-value-and-function-argument-type-annotations -let update (msg: Msg) (model: Model) : Model = model // See https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#surround-return-type-annotations-with-white-space -``` - -`{ defaultConfig with SpaceBeforeColon = true }` - -```fsharp -type Point = { x : int; y : int } -let myValue : int = 42 -let update (msg : Msg) (model : Model) : Model = model -``` - -### fsharp_space_after_comma - -Adds a space after `,` in tuples. -Default = true. - -`defaultConfig` - -```fsharp -myValue.SomeFunction(foo, bar, somethingElse) -(a, b, c) -``` - -`{ defaultConfig with SpaceAfterComma = false }` - -```fsharp -myValue.SomeFunction(foo,bar,somethingElse) -(a,b,c) -``` - -### fsharp_space_before_semicolon - -Adds a space before `;` in records, arrays, lists, etc. -Default = false. - -`defaultConfig` - -```fsharp -let a = [ 1; 2; 3 ] -let b = [| foo; bar |] -type C = { X: int; Y: int } -``` - -`{ defaultConfig with SpaceBeforeSemicolon = true }` - -```fsharp -let a = [ 1 ; 2 ; 3 ] -let b = [| foo ; bar |] -type C = { X: int ; Y: int } -``` - -### fsharp_space_after_semicolon - -Adds a space after `;` in records, arrays, lists, etc. -Default = true. - -`defaultConfig` - -```fsharp -let a = [ 1; 2; 3 ] -let b = [| foo; bar |] -type C = { X: int; Y: int } -``` - -`{ defaultConfig with SpaceAfterSemicolon = false }` - -```fsharp -let a = [ 1;2;3 ] -let b = [| foo;bar |] -type C = { X: int;Y: int } -``` - -### fsharp_space_around_delimiter - -Adds a space around delimiters like `[`,`[|`,`{`. -Default = true. - -`defaultConfig` - -```fsharp -let a = [ 1;2;3 ] -let b = [| 4;5;6 |] -``` - -`{ defaultConfig with SpaceAroundDelimiter = false }` - -```fsharp -let a = [1;2;3] -let b = [|4;5;6|] -``` -### fsharp_max_if_then_short_width - -Control the maximum length for which if/then expression without an else expression can be on one line. -The [Microsoft F# style guide](https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions) recommends to never write such an expression in one line. -> If the else expression is absent, it is recommended to never to write the entire expression in one line. -Default = 0. - -`defaultConfig` - -```fsharp -if a then - () -``` - -`{ defaultConfig with MaxIfThenShortWidth = 15 }` - -```fsharp -if a then () -``` - -### fsharp_max_if_then_else_short_width - -Fantomas by default follows the if/then/else conventions listed in the [Microsoft F# style guide](https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions). -There is stated: - -> Indentation of conditionals depends on the size and complexity of the expressions that make them up. Write them on one line when: -> cond, e1, and e2 are short -> e1 and e2 are not if/then/else expressions themselves. - -This setting facilitates this by determining the maximum character width where the if/then/else expression stays in one line. -Default = 40. - -`defaultConfig` - -```fsharp -if myCheck then truth else bogus -``` - -`{ defaultConfig with MaxIfThenElseShortWidth = 10 }` - -```fsharp -if myCheck then - truth -else - bogus -``` - -### fsharp_max_infix_operator_expression - -Control the maximum length for which infix expression can be on one line. -Default = 50. - -`defaultConfig` - -```fsharp -let WebApp = - route "/ping" >=> authorized >=> text "pong" -``` - -`{ defaultConfig with MaxInfixOperatorExpression = 20 }` - -```fsharp -let WebApp = - route "/ping" - >=> authorized - >=> text "pong" -``` - -### fsharp_max_record_width - -Control the maximum width for which records should be in one line. Default = 40. -Requires `fsharp_record_multiline_formatter` to be `character_width` to take -effect. - -`defaultConfig` - -```fsharp -type MyRecord = { X: int; Y: int; Length: int } -let myInstance = { X = 10; Y = 20; Length = 90 } -``` - -`{ defaultConfig with MaxRecordWidth = 20 }` - -```fsharp -type MyRecord = - { X: int - Y: int - Length: int } - -let myInstance = - { X = 10 - Y = 20 - Length = 90 } -``` - -### fsharp_max_record_number_of_items - -Control the maximum number of fields for which records should be in one line. -Default = 1. Requires `fsharp_record_multiline_formatter` to be -`number_of_items` to take effect. - -`defaultConfig` - -```fsharp -type R = { x: int } - -type S = { x: int; y: string } - -type T = { x: int; y: string; z: float } - -let myRecord = { r = 3 } - -let myRecord' = { r with x = 3 } - -let myRecord'' = { r with x = 3; y = "hello" } - -let myRecord''' = { r with x = 3; y = "hello"; z = 0.0 } -``` - -`{ defaultConfig with MaxRecordSize = 2; RecordMultilineFormatter = -MultilineFormatterType.NumberOfItems }` - -```fsharp -type R = { x: int } - -type S = { x: int; y: string } - -type T = - { x: int - y: string - z: float } - -let myRecord = { r = 3 } - -let myRecord' = { r with x = 3 } - -let myRecord'' = { r with x = 3; y = "hello" } - -let myRecord''' = - { r with - x = 3 - y = "hello" - z = 0.0 } -``` - -### fsharp_record_multiline_formatter - -Split records expressions/statements into multiple lines based on the given -condition. `character_width` uses character count of the expression, controlled -by `fsharp_max_record_width`. `number_of_items` uses the number of fields in the -record, controlled by `fsharp_max_record_number_of_items`. Default = -`character_width`. Note that in either case, record expressions/statements are -still governed by `max_line_length`. - -`defaultConfig` - -```fsharp -type R = { x: int } - -type S = { x: int; y: string } - -let myRecord = { r = 3 } - -let myRecord' = { r with x = 3 } - -let myRecord'' = { r with x = 3; y = "hello" } -``` - -`{ defaultConfig with RecordMultilineFormatter = -MultilineFormatterType.NumberOfItems }` - -```fsharp -type R = { x: int } - -type S = - { x: int - y: string } - -let myRecord = { x = 3 } - -let myRecord' = { r with x = 3 } - -let myRecord'' = - { r with - x = 3 - y = "hello" } -``` - -### fsharp_max_array_or_list_width - -Control the maximum width for which lists and arrays can be in one line. Default -= 40. Requires `fsharp_array_or_list_multiline_formatter` to be -`character_width` to take effect. - -`defaultConfig` - -```fsharp -let myArray = [| one; two; three |] -``` - -`{ defaultConfig with MaxArrayOrListWidth = 20 }` - -```fsharp -let myArray = - [| one - two - three |] -``` - -### fsharp_max_array_or_list_number_of_items - -Control the maximum number of elements for which lists and arrays can be in -one line. Default = 1. Requires `fsharp_array_or_list_multiline_formatter` to be -`number_of_items` to take effect. - -`defaultConfig` - -```fsharp -let myList = [ one; two ] - -let myArray = [| one; two; three |] -``` - -`{ defaultConfig with MaxArrayOrListNumberOfItems = 2; ArrayOrListMultilineFormatter = -MultilineFormatterType.NumberOfItems }` - -```fsharp -let myList = [ one; two ] - -let myArray = - [| one - two - three |] -``` - -### fsharp_array_or_list_multiline_formatter - -Split arrays and lists into multiple lines based on the given condition. -`character_width` uses character count of the expression, controlled by -`fsharp_max_array_or_list_width`. `number_of_items` uses the number of elements -in the array or list, controlled by `fsharp_max_array_or_list_number_of_items`. -Default = `character_width`. Note that in either case, list expressions are -still governed by `max_line_length`. - -`defaultConfig` - -```fsharp -let myArray = [| one; two; three |] -``` - -`{ defaultConfig with ArrayOrListMultilineFormatter = -MultilineFormatterType.NumberOfItems }` - -```fsharp -let myArray = - [| one - two - three |] -``` - -### fsharp_max_value_binding_width - -Control the maximum expression width for which let and member value/property bindings should be in one line. -The width is that of the pattern for the binding plus the implementating expression but not the keywords (e.g. "let"). -Default = 80. - -`defaultConfig` - -```fsharp -let title = "Great title of project" - -type MyType() = - member this.HelpText = "Some help text" -``` - -`{ defaultConfig with MaxValueBindingWidth = 10 }` - -```fsharp -let title = - "Great title of project" - -type MyType() = - member this.HelpText = - "Some help text" -``` - -### fsharp_max_function_binding_width - -Control the maximum width for which function and member bindings should be in one line. -Default = 40. - -`defaultConfig` - -```fsharp -let printScore score total = printfn "%i / %i" score total - -type Triangle() = - member this.CalculateSurface(width: int, height: int) = width * height / 2 -``` - -`{ defaultConfig with MaxFunctionBindingWidth = 10 }` - -```fsharp -let printScore score total = - printfn "%i / %i" score total - -type Triangle() = - member this.CalculateSurface(width: int, height: int) = - width * height / 2 -``` - -### fsharp_max_dot_get_expression_width - -Control the maximum width for which (nested) [SynExpr.DotGet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#DotGet) expressions should be in one line. -Default = 50. - -`defaultConfig` - -```fsharp -let job = - JobBuilder - .UsingJobData(jobDataMap) - .Create() - .Build() -``` - -`{ defaultConfig with MaxDotGetExpressionWidth = 100 }` - -```fsharp -let job = - JobBuilder.UsingJobData(jobDataMap).Create().Build() -``` - -### fsharp_multiline_block_brackets_on_same_column - -Alternative way of formatting records, arrays and lists. This will align the braces at the same column level. -Default = false. - -`defaultConfig` - -```fsharp -let myRecord = - { Level = 1 - Progress = "foo" - Bar = "bar" - Street = "Bakerstreet" - Number = 42 } - -type Range = - { From: float - To: float } - -let a = - [| (1, 2, 3) - (4, 5, 6) - (7, 8, 9) |] -``` - -`{ defaultConfig with MultilineBlockBracketsOnSameColumn = true }` - -```fsharp -let myRecord = - { - Level = 1 - Progress = "foo" - Bar = "bar" - Street = "Bakerstreet" - Number = 42 - } - -type Range = - { - From: float - To: float - } - -let a = - [| - (1, 2, 3) - (4, 5, 6) - (7, 8, 9) - |] -``` - -### fsharp_newline_between_type_definition_and_members - -Adds a new line between a type definition and its first member. -Default = false. - -`defaultConfig` - -```fsharp -type Range = - { From: float - To: float } - member this.Length = this.To - this.From -``` - -`{ defaultConfig with NewlineBetweenTypeDefinitionAndMembers = true }` - -```fsharp -type Range = - { From: float - To: float } - - member this.Length = this.To - this.From -``` - -### fsharp_align_function_signature_to_indentation - -When a function signature exceeds the `max_line_length`, Fantomas will put all parameters on separate lines. -This setting also places the equals sign and return type on a new line. -Default = false. - -`defaultConfig` - -```fsharp -[] -let run - ([] req: HttpRequest) - (log: ILogger) - : HttpResponse = - Http.main CodeFormatter.GetVersion format FormatConfig.FormatConfig.Default log req -``` - -`{ defaultConfig with AlignFunctionSignatureToIndentation = true }` - -```fsharp -[] -let run - ([] req: HttpRequest) - (log: ILogger) - : HttpResponse - = - Http.main CodeFormatter.GetVersion format FormatConfig.FormatConfig.Default log req -``` - -### fsharp_alternative_long_member_definitions - -Provides an alternative way of formatting long member and constructor definitions, -where the difference is mainly in the equal sign and returned type placement. -Default = false. - -`defaultConfig` - -```fsharp -type C - ( - aVeryLongType: AVeryLongTypeThatYouNeedToUse, - aSecondVeryLongType: AVeryLongTypeThatYouNeedToUse, - aThirdVeryLongType: AVeryLongTypeThatYouNeedToUse - ) = - class - end - -type D() = - member _.LongMethodWithLotsOfParameters - ( - aVeryLongParam: AVeryLongTypeThatYouNeedToUse, - aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse, - aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse - ) : ReturnType = - 42 -``` - -`{ defaultConfig with AlternativeLongMemberDefinitions = true }` - -```fsharp -type C - ( - aVeryLongType: AVeryLongTypeThatYouNeedToUse, - aSecondVeryLongType: AVeryLongTypeThatYouNeedToUse, - aThirdVeryLongType: AVeryLongTypeThatYouNeedToUse - ) - = - class - end - -type D() = - member _.LongMethodWithLotsOfParameters - ( - aVeryLongParam: AVeryLongTypeThatYouNeedToUse, - aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse, - aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse - ) - : ReturnType - = - 42 -``` - -### fsharp_multi_line_lambda_closing_newline - -Places the closing parenthesis of a multiline lambda argument on the next line. -Default = false. - -`defaultConfig` - -```fsharp -let printListWithOffset a list1 = - List.iter - (fun { ItemOne = a } -> - // print - printfn "%s" a) - list1 - -let printListWithOffset a list1 = - list1 - |> List.iter - (fun elem -> - // print stuff - printfn "%d" (a + elem)) -``` - -`{ defaultConfig with MultiLineLambdaClosingNewline = true }` - -```fsharp -let printListWithOffset a list1 = - List.iter - (fun { ItemOne = a } -> - // print - printfn "%s" a - ) - list1 - -let printListWithOffset a list1 = - list1 - |> List.iter (fun elem -> - // print stuff - printfn "%d" (a + elem) - ) -``` - -### fsharp_experimental_keep_indent_in_branch - -Breaks the normal indentation flow for the last branch of a pattern match or if/then/else expression. -Only when the pattern match or if/then/else is the return value of a function or member. - -*This feature is considered experimental and is subject to change* - -`defaultConfig` - -```fsharp -let main argv = - let args = parse argv - - let instructions = Library.foo args - - if args.DryRun = RunMode.Dry then - printfn "Would execute actions, but --dry-run was supplied: %+A" instructions - 0 - else - // proceed with main method - let output = Library.execute instructions - // do more stuff - 0 -``` - -`{ defaultConfig with KeepIndentInBranch = true }` - -```fsharp -let main argv = - let args = parse argv - - let instructions = Library.foo args - - if args.DryRun = RunMode.Dry then - printfn "Would execute actions, but --dry-run was supplied: %+A" instructions - 0 - else - // proceed with main method - let output = Library.execute instructions - // do more stuff - 0 -``` - -### fsharp_blank_lines_around_nested_multiline_expressions - -Surround **nested** multi-line expressions with blank lines. -Existing blank lines are always preserved (via trivia), with exception when [fsharp_keep_max_number_of_blank_lines](#fsharp_keep_max_number_of_blank_lines) is used. -Top level expressions will always follow the [2020 blank lines revision](https://github.com/fsprojects/fantomas/blob/master/docs/FormattingConventions.md#2020-revision) principle. -Default = true. - -`defaultConfig` - -```fsharp -let topLevelFunction () = - printfn "Something to print" - - try - nothing () - with - | ex -> - splash () - () - -let secondTopLevelFunction () = - // ... - () -``` - -`{ defaultConfig with BlankLinesAroundNestedMultilineExpressions = false }` - -```fsharp -let topLevelFunction () = - printfn "Something to print" - try - nothing () - with - | ex -> - splash () - () - -let secondTopLevelFunction () = - // ... - () -``` - -### fsharp_bar_before_discriminated_union_declaration - -Always use a `|` before every case in the declaration of a discriminated union. If `false`, a `|` character is used only in multiple-case discriminated unions, and is omitted in short single-case DUs. -Default = false. - -```fsharp -type MyDU = Short of int -``` - -`{ defaultConfig with BarBeforeDiscriminatedUnionDeclaration = true }` - -```fsharp -type MyDU = | Short of int -``` - -### fsharp_experimental_stroustrup_style - -Please contribute to https://github.com/fsprojects/fantomas/issues/1408. - -### fsharp_keep_max_number_of_blank_lines - -Set maximal number of consecutive blank lines to keep from original source. It doesn't change number of new blank lines generated by Fantomas. -Default=100 - -`defaultConfig` - -```fsharp -open Foo - - -let x = 42 -``` - -`{ defaultConfig with KeepMaxNumberOfBlankLines = 1 }` - -```fsharp -open Foo - -let x = 42 -``` - - -### fsharp_strict_mode - -If being set, pretty printing is only done via ASTs. Compiler directives, inline comments and block comments will be ignored. -There are numerous situations when the information in the AST alone cannot restore the original code. -**Please do not use this setting for formatting hand written code!** -Valid use-case of this settings is code generation in projects like [FsAst](https://github.com/ionide/FsAst) and [Myriad](https://github.com/MoiraeSoftware/myriad). -Default = false. - -`hand written code` - -```fsharp -// some great comment -let add a b = -#if INTERACTIVE - 42 -#else - a + b -#endif -``` - -`{ defaultConfig with StrictMode = true }` - -```fsharp -let add a b = a + b -``` - -
- Previous - Next -
\ No newline at end of file diff --git a/docs/images/gresearch.svg b/docs/images/gresearch.svg new file mode 100644 index 0000000000..1894940a0d --- /dev/null +++ b/docs/images/gresearch.svg @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/docs/online_tool_usage.gif b/docs/online_tool_usage.gif new file mode 100644 index 0000000000..ce1adf53d9 Binary files /dev/null and b/docs/online_tool_usage.gif differ