From 07fb56b072fdcfd6b4fa7fd61bfa9032b06112f8 Mon Sep 17 00:00:00 2001 From: Florian Verdonck Date: Mon, 6 Jul 2020 21:00:49 +0200 Subject: [PATCH] Add support for editorconfig (#940) * Editorconfig WIP * Merging editorconfig.core with ILRepack * Replace EditorConfig.Core dll with unlisted nuget package. * Renamed IndentSpaceNum and PageWidth * Remove json configuration * Added unit tests for editorconfig support. * Update commandline tool * Bump to alpha 12 * Restore unit tests * Update code comment --- RELEASE_NOTES.md | 3 +- docs/Documentation.md | 84 +++----- paket.dependencies | 2 + paket.lock | 20 +- .../ConfigTests.fs | 20 +- .../Fantomas.CoreGlobalTool.Tests.fsproj | 2 +- .../TestHelpers.fs | 5 +- .../Fantomas.CoreGlobalTool.fsproj | 2 +- src/Fantomas.CoreGlobalTool/Program.fs | 61 ++---- src/Fantomas.Tests/AppTests.fs | 12 +- src/Fantomas.Tests/CheckTests.fs | 8 +- src/Fantomas.Tests/CompilerDirectivesTests.fs | 6 +- .../ComputationExpressionTests.fs | 2 +- src/Fantomas.Tests/ContextTests.fs | 2 +- src/Fantomas.Tests/ElmishTests.fs | 2 +- src/Fantomas.Tests/FSharpScriptTests.fs | 14 +- src/Fantomas.Tests/Fantomas.Tests.fsproj | 3 +- ...ormatConfigEditorConfigurationFileTests.fs | 175 ++++++++++++++++ .../FormatConfigJsonConfigurationFileTests.fs | 186 ------------------ src/Fantomas.Tests/FunctionDefinitionTests.fs | 10 +- src/Fantomas.Tests/IfThenElseTests.fs | 22 +-- src/Fantomas.Tests/InterfaceTests.fs | 2 +- .../KeepIfThenInSameLineTests.fs | 4 +- src/Fantomas.Tests/LambdaTests.fs | 8 +- src/Fantomas.Tests/ListTests.fs | 14 +- ...ineBlockBracketsOnSameColumnRecordTests.fs | 4 +- src/Fantomas.Tests/OperatorTests.fs | 4 +- src/Fantomas.Tests/PatternMatchingTests.fs | 6 +- src/Fantomas.Tests/PipingTests.fs | 2 +- src/Fantomas.Tests/TypeDeclarationTests.fs | 12 +- src/Fantomas/CodeFormatter.fs | 2 +- src/Fantomas/CodeFormatter.fsi | 5 +- src/Fantomas/CodeFormatterImpl.fs | 36 +--- src/Fantomas/CodePrinter.fs | 4 +- src/Fantomas/ConfigFile.fs | 69 ------- src/Fantomas/Context.fs | 26 +-- src/Fantomas/EditorConfig.fs | 62 +++++- src/Fantomas/FakeHelpers.fs | 15 +- src/Fantomas/Fantomas.fsproj | 16 +- src/Fantomas/FormatConfig.fs | 28 +-- src/Fantomas/JsonConfig.fs | 20 -- src/Fantomas/Utils.fs | 16 -- src/Fantomas/paket.references | 4 +- src/Fantomas/schema.json | 85 -------- 44 files changed, 444 insertions(+), 641 deletions(-) delete mode 100644 src/Fantomas.Tests/FormatConfigJsonConfigurationFileTests.fs delete mode 100644 src/Fantomas/ConfigFile.fs delete mode 100644 src/Fantomas/JsonConfig.fs delete mode 100644 src/Fantomas/schema.json diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7ca3ff2430..5345ddb907 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,7 @@ -### 4.0.0-alpha-011 - 06/2020 +### 4.0.0-alpha-012 - 06/2020 * WIP for [#705](https://github.com/fsprojects/fantomas/issues/705) * FCS 36 +* Replaced json configuration with .editorconfig ### 3.3.0 - 02/2020 diff --git a/docs/Documentation.md b/docs/Documentation.md index 4f0d004080..02db56ff51 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -244,61 +244,39 @@ More preferences will be added depending on use cases. ##### `--config ` -Use a JSON configuration file based on a [schema](../src/Fantomas/schema.json) to set the formatting options. - -A default configuration file would look like -```json -{ - "IndentSpaceNum":4, - "PageWidth":120, - "SemicolonAtEndOfLine":false, - "SpaceBeforeParameter":true, - "SpaceBeforeLowercaseInvocation":true, - "SpaceBeforeUppercaseInvocation":false, - "SpaceBeforeClassConstructor":false, - "SpaceBeforeMember":false, - "SpaceBeforeColon":false, - "SpaceAfterComma":true , - "SpaceBeforeSemicolon": false, - "SpaceAfterSemicolon":true , - "IndentOnTryWith":false, - "SpaceAroundDelimiter":true , - "MaxIfThenElseShortWidth":40, - "KeepIfThenInSameLine":false, - "MaxInfixOperatorExpression":50, - "MaxRecordWidth":40, - "MaxArrayOrListWidth":40, - "MaxValueBindingWidth":40, - "MaxFunctionBindingWidth":40, - "MultilineBlockBracketsOnSameColumn":false, - "NewlineBetweenTypeDefinitionAndMembers":false, - "MaxElmishWidth": 40, - "StrictMode":false -} +Use an .editorconfig configuration file to set the formatting options. + +A default .editorconfig file would look like +```ini +[*.fs] +indent_size=4 +max_line_length=120 +fsharp_semicolon_at_end_of_line=false +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_indent_on_try_with=false +fsharp_space_around_delimiter=true +fsharp_max_if_then_else_short_width=40 +fsharp_max_infix_operator_expression=50 +fsharp_max_record_width=40 +fsharp_max_array_or_list_width=40 +fsharp_max_value_binding_width=40 +fsharp_max_function_binding_width=40 +fsharp_multiline_block_brackets_on_same_column=false +fsharp_newline_between_type_definition_and_members=false +fsharp_keep_if_then_in_same_line=false +fsharp_max_elmish_width=40 +fsharp_single_argument_web_mode=false +fsharp_strict_mode=false ``` -However, **a configuration file overwrites options** from [the default configuration](../src/Fantomas/FormatConfig.fs). - -The argument passed after `--config ` can be a file named `fantomas-config.json` or a folder. -In both cases a Fantomas will try and locate `fantomas-config.json` in all the parent folders. -The found configuration files are then being applied to to the default configuration from top to bottom. - -F.ex. - -``` -C:\ - Temp\ - fantomas-config.json - MyProject\ - fantomas-config.json -``` - -Formatting with `dotnet fantomas MyFile.fs --config "C:\Temp\MyProject"` will first apply the settings in `C:\Temp\fantomas-config.json` and then those of `C:\Temp\MyProject\fantomas-config.json`. - -If the `--config` is used in combination with other settings, the configuration is applied first and then the other arguments. - -Warnings will be given if settings in the configuration no longer apply for the current version of Fantomas. - ### Using the API See [CodeFormatter.fsi](../src/Fantomas/CodeFormatter.fsi) to view the API of Fantomas. \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies index d4fab929d3..6f8f0d0885 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -12,5 +12,7 @@ nuget NUnit3TestAdapter 3.15.1 nuget NunitXml.TestLogger nuget Argu nuget BenchmarkDotNet +nuget Fantomas.EditorConfig.Core copy_local: true +nuget ILRepack.MSBuild.Task copy_local: true github: fsprojects/fantomas:829faa6ba834f99afed9b4434b3a1680536474b2 src/Fantomas/CodePrinter.fs \ No newline at end of file diff --git a/paket.lock b/paket.lock index e7da1b0ad5..666bbe18b5 100644 --- a/paket.lock +++ b/paket.lock @@ -23,6 +23,7 @@ NUGET System.ValueTuple (>= 4.5) BenchmarkDotNet.Annotations (0.12.1) CommandLineParser (2.8) + Fantomas.EditorConfig.Core (1.0) - copy_local: true FsCheck (2.14) FSharp.Core (>= 4.2.3) FSharp.Compiler.Service (36.0.1) @@ -40,6 +41,17 @@ NUGET NETStandard.Library (>= 2.0.3) NUnit (>= 3.12 < 4.0) Iced (1.7) + ILRepack.MSBuild.Task (2.0.13) - copy_local: true + Microsoft.Build.Framework (>= 15.9.20) + Microsoft.Build.Utilities.Core (>= 15.9.20) + Microsoft.Build.Framework (16.6) - copy_local: true + System.Security.Permissions (>= 4.7) + Microsoft.Build.Utilities.Core (16.6) - copy_local: true + Microsoft.Build.Framework (>= 16.6) + Microsoft.Win32.Registry (>= 4.3) + System.Collections.Immutable (>= 1.5) + System.Security.Permissions (>= 4.7) + System.Text.Encoding.CodePages (>= 4.0.1) Microsoft.CodeAnalysis.Analyzers (3.0) Microsoft.CodeAnalysis.Common (3.6) Microsoft.CodeAnalysis.Analyzers (>= 3.0) @@ -85,7 +97,7 @@ NUGET System.Memory (>= 4.5.3) - restriction: || (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netcoreapp2.1)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) System.Security.AccessControl (>= 4.7) System.Security.Principal.Windows (>= 4.7) - Microsoft.Win32.SystemEvents (4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) + Microsoft.Win32.SystemEvents (4.7) - copy_local: true, restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) Microsoft.NETCore.Platforms (>= 3.1) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) @@ -190,7 +202,7 @@ NUGET System.Threading.Tasks (>= 4.3) System.Threading.Thread (>= 4.3) System.Threading.ThreadPool (>= 4.3) - System.Drawing.Common (4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) + System.Drawing.Common (4.7) - copy_local: true, restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) Microsoft.NETCore.Platforms (>= 3.1) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) Microsoft.Win32.SystemEvents (>= 4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) System.Globalization (4.3) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp1.0)) @@ -301,7 +313,7 @@ NUGET System.Security.Principal.Windows (>= 4.7) System.Security.Cryptography.ProtectedData (4.7) System.Memory (>= 4.5.3) - restriction: || (&& (== netcoreapp3.1) (< netcoreapp2.1)) (== netstandard2.0) - System.Security.Permissions (4.7) + System.Security.Permissions (4.7) - copy_local: true System.Security.AccessControl (>= 4.7) System.Windows.Extensions (>= 4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) System.Security.Principal.Windows (4.7) @@ -334,7 +346,7 @@ NUGET System.Runtime (>= 4.3) System.Runtime.Handles (>= 4.3) System.ValueTuple (4.5) - System.Windows.Extensions (4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) + System.Windows.Extensions (4.7) - copy_local: true, restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) System.Drawing.Common (>= 4.7) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.0)) System.Xml.ReaderWriter (4.3.1) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp1.0)) System.Collections (>= 4.3) diff --git a/src/Fantomas.CoreGlobalTool.Tests/ConfigTests.fs b/src/Fantomas.CoreGlobalTool.Tests/ConfigTests.fs index be690ea25a..4458cbad92 100644 --- a/src/Fantomas.CoreGlobalTool.Tests/ConfigTests.fs +++ b/src/Fantomas.CoreGlobalTool.Tests/ConfigTests.fs @@ -3,20 +3,28 @@ module Fantomas.CoreGlobalTool.Tests.ConfigTests open NUnit.Framework open FsUnit open Fantomas.CoreGlobalTool.Tests.TestHelpers -open Fantomas.FormatConfig [] let ``config file in working directory should not require relative prefix, 821`` () = use fileFixture = - new TemporaryFileCodeSample("let a = 9") + new TemporaryFileCodeSample("let a = // foo + 9") use configFixture = - new ConfigurationFile({ FormatConfig.Default with - IndentSpaceNum = 2 }) + new ConfigurationFile(""" +[*.fs] +indent_size=2 +""" ) let (exitCode, output) = - runFantomasTool (sprintf "--config fantomas-config.json %s" fileFixture.Filename) + runFantomasTool fileFixture.Filename exitCode |> should equal 0 output - |> should startWith (sprintf "Processing %s" fileFixture.Filename) \ No newline at end of file + |> should startWith (sprintf "Processing %s" fileFixture.Filename) + + let result = System.IO.File.ReadAllText(fileFixture.Filename) + result + |> should equal """let a = // foo + 9 +""" \ No newline at end of file diff --git a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj index 2013bbe68a..84138af258 100644 --- a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj +++ b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 false false - 4.0.0-alpha-011 + 4.0.0-alpha-012 FS0988 diff --git a/src/Fantomas.CoreGlobalTool.Tests/TestHelpers.fs b/src/Fantomas.CoreGlobalTool.Tests/TestHelpers.fs index c648a18e55..fed44432d9 100644 --- a/src/Fantomas.CoreGlobalTool.Tests/TestHelpers.fs +++ b/src/Fantomas.CoreGlobalTool.Tests/TestHelpers.fs @@ -33,9 +33,8 @@ type OutputFile internal () = if File.Exists(filename) then File.Delete(filename) -type ConfigurationFile internal (config: Fantomas.FormatConfig.FormatConfig) = - let filename = Path.Join(Path.GetTempPath(), "fantomas-config.json") - let content = Config.configToJson config +type ConfigurationFile internal (content: string) = + let filename = Path.Join(Path.GetTempPath(), ".editorconfig") do File.WriteAllText(filename, content) member _.Filename: string = filename interface IDisposable with diff --git a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj index fe298a0430..2aba4075c7 100644 --- a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj +++ b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 fantomas True - 4.0.0-alpha-011 + 4.0.0-alpha-012 fantomas-tool diff --git a/src/Fantomas.CoreGlobalTool/Program.fs b/src/Fantomas.CoreGlobalTool/Program.fs index bd8182d450..230ef211ce 100644 --- a/src/Fantomas.CoreGlobalTool/Program.fs +++ b/src/Fantomas.CoreGlobalTool/Program.fs @@ -8,16 +8,14 @@ open System.Text let extensions = set [| ".fs"; ".fsx"; ".fsi"; ".ml"; ".mli"; |] type Arguments = - | [] Recurse + | [] Recurse | [] Force | [] Profile | [] Fsi of string | [] Stdin | [] Stdout | [] Out of string - | [] Indent of int | [] Check - | [] Config of string | [] Version | [] Input of string with @@ -31,9 +29,7 @@ with | Fsi _ -> "Read F# source from stdin as F# signatures." | Stdin -> "Read F# source from standard input." | Stdout -> " Write the formatted source code to standard output." - | Indent _ -> "Set number of spaces for indentation (default = 4). The value should be between 1 and 10." | Check -> "Don't format files, just check if they have changed. Exits with 0 if it's formatted correctly, with 1 if some files need formatting and 99 if there was an internal error" - | Config _ -> "Use configuration found in file or folder." | Version -> "Displays the version of Fantomas" | Input _ -> sprintf "Input path: can be a folder or file with %s extension." (Seq.map (fun s -> "*" + s) extensions |> String.concat ",") @@ -108,9 +104,9 @@ let processSourceString isFsiFile s (tw : Choice) config = |> Async.RunSynchronously /// Format inFile and write to text writer -let processSourceFile inFile (tw : TextWriter) config = +let processSourceFile inFile (tw : TextWriter) = async { - let! formatted = inFile |> FakeHelpers.formatFileAsync config + let! formatted = FakeHelpers.formatFileAsync inFile match formatted with | FakeHelpers.FormatResult.Formatted(_, formattedContent) -> @@ -159,8 +155,8 @@ let private reportCheckResults (output: TextWriter) (checkResult: FakeHelpers.Ch |> List.map (fun filename -> sprintf "%s needs formatting" filename) |> Seq.iter output.WriteLine -let runCheckCommand (config: FormatConfig) (recurse: bool) (inputPath: InputPath) : int = - let check files = Async.RunSynchronously (FakeHelpers.checkCode config files) +let runCheckCommand (recurse: bool) (inputPath: InputPath) : int = + let check files = Async.RunSynchronously (FakeHelpers.checkCode files) let processCheckResult (checkResult: FakeHelpers.CheckResult) = if checkResult.IsValid then @@ -228,23 +224,7 @@ let main argv = let recurse = results.Contains<@ Arguments.Recurse @> let version = results.TryGetResult<@ Arguments.Version @> - let config = - results.TryGetResult<@ Arguments.Config @> - |> Option.map (fun configPath -> - let configResult = CodeFormatter.ReadConfiguration configPath - match configResult with - | Success s -> s - | PartialSuccess (ps, warnings) -> - List.iter (writeInColor ConsoleColor.DarkYellow) warnings - ps - | Failure e -> - writeInColor ConsoleColor.DarkRed "Couldn't process one or more Fantomas configuration files, falling back to the default configuration" - writeInColor ConsoleColor.DarkRed (e.ToString()) - FormatConfig.Default - ) - |> Option.defaultValue FormatConfig.Default - - let fileToFile (inFile : string) (outFile : string) config = + let fileToFile (inFile : string) (outFile : string) = try printfn "Processing %s" inFile let hasByteOrderMark = hasByteOrderMark inFile @@ -258,9 +238,9 @@ let main argv = if profile then File.ReadLines(inFile) |> Seq.length |> printfn "Line count: %i" - time (fun () -> processSourceFile inFile buffer config) + time (fun () -> processSourceFile inFile buffer) else - processSourceFile inFile buffer config + processSourceFile inFile buffer buffer.Flush() printfn "%s has been written." outFile with @@ -297,12 +277,13 @@ let main argv = if force then stdout.Write(s) - let processFile inputFile outputFile config = + let processFile inputFile outputFile = if inputFile <> outputFile then - fileToFile inputFile outputFile config + fileToFile inputFile outputFile else printfn "Processing %s" inputFile let content = File.ReadAllText inputFile + let config = CodeFormatter.ReadConfiguration(inputFile) stringToFile content inputFile config let processFolder inputFolder outputFolder = @@ -317,13 +298,13 @@ let main argv = Path.Combine(outputFolder, suffix) else i - processFile i o config) + processFile i o) - let fileToStdOut inFile config = + let fileToStdOut inFile = try use buffer = new StringWriter() // Don't record running time when output formatted content to console - processSourceFile inFile buffer config + processSourceFile inFile buffer stdout.Write(buffer.ToString()) with | exn -> @@ -338,7 +319,7 @@ let main argv = let check = results.Contains<@ Arguments.Check @> if check then inputPath - |> runCheckCommand config recurse + |> runCheckCommand recurse |> exit else match inputPath, outputPath with @@ -346,18 +327,18 @@ let main argv = eprintfn "Input path is missing..." exit 1 | InputPath.Folder p1, OutputPath.Notknown -> processFolder p1 p1 - | InputPath.File p1, OutputPath.Notknown -> processFile p1 p1 config + | InputPath.File p1, OutputPath.Notknown -> processFile p1 p1 | InputPath.File p1, OutputPath.IO p2 -> - processFile p1 p2 config + processFile p1 p2 | InputPath.Folder p1, OutputPath.IO p2 -> processFolder p1 p2 | InputPath.StdIn s, OutputPath.IO p -> - stringToFile s p config + stringToFile s p FormatConfig.Default | InputPath.StdIn s, OutputPath.Notknown | InputPath.StdIn s, OutputPath.StdOut -> - stringToStdOut s config + stringToStdOut s FormatConfig.Default | InputPath.File p, OutputPath.StdOut -> - fileToStdOut p config + fileToStdOut p | InputPath.Folder p, OutputPath.StdOut -> allFiles recurse p - |> Seq.iter (fun p -> fileToStdOut p config) + |> Seq.iter fileToStdOut 0 \ No newline at end of file diff --git a/src/Fantomas.Tests/AppTests.fs b/src/Fantomas.Tests/AppTests.fs index c7ffe1179d..dc8bb19c05 100644 --- a/src/Fantomas.Tests/AppTests.fs +++ b/src/Fantomas.Tests/AppTests.fs @@ -12,7 +12,7 @@ let a = b |> List.exists (fun p -> p.a && p.b |> List.exists (fun o -> o.a = "lorem ipsum dolor sit amet")) - """ { config with PageWidth = 80 } + """ { config with MaxLineLength = 80 } |> prepend newline |> should equal """ let a = @@ -63,7 +63,7 @@ let a s = s (llloooooooooooooooooooooooooo s) (llloooooooooooooooooooooooooo s)" - { config with PageWidth = 50 } + { config with MaxLineLength = 50 } |> prepend newline |> should equal @" let a s = @@ -91,7 +91,7 @@ let ``should split parameters over multiple lines when they exceed page width``( ReportProblem compoundBalance None currency address sessionCachedNetworkData () ) - ()""" { config with PageWidth = 60 } + ()""" { config with MaxLineLength = 60 } |> prepend newline |> should equal """ module Caching = @@ -128,7 +128,7 @@ let ``should split single parameter over multiple lines when it exceeds page wid ReportProblem looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong () ) - ()""" { config with PageWidth = 60 } + ()""" { config with MaxLineLength = 60 } |> prepend newline |> should equal """ module Caching = @@ -161,7 +161,7 @@ let ``should not split parameters over multiple lines when they do not exceed pa ReportProblem compoundBalance None currency address sessionCachedNetworkData () ) - ()""" { config with PageWidth = 120 } + ()""" { config with MaxLineLength = 120 } |> prepend newline |> should equal """ module Caching = @@ -191,7 +191,7 @@ let ``should not split single parameter over multiple lines when it does not exc ReportProblem compoundBalance () ) - ()""" { config with PageWidth = 120 } + ()""" { config with MaxLineLength = 120 } |> prepend newline |> should equal """ module Caching = diff --git a/src/Fantomas.Tests/CheckTests.fs b/src/Fantomas.Tests/CheckTests.fs index 54942625fb..3791e3da76 100644 --- a/src/Fantomas.Tests/CheckTests.fs +++ b/src/Fantomas.Tests/CheckTests.fs @@ -6,8 +6,6 @@ open Fantomas.FormatConfig open Fantomas.FakeHelpers open Fantomas.Tests.TestHelper -let private config = FormatConfig.Default - [] let NeedsFormatting = """module A @@ -30,7 +28,7 @@ let ``formatted files should report no changes``() = let result = fileFixture.Filename |> Seq.singleton - |> checkCode config + |> checkCode |> Async.RunSynchronously result.NeedsFormatting |> should equal false @@ -43,7 +41,7 @@ let ``files with errors should report an internal error``() = let result = fileFixture.Filename |> Seq.singleton - |> checkCode config + |> checkCode |> Async.RunSynchronously result.HasErrors |> should equal true @@ -56,7 +54,7 @@ let ``files that need formatting should report that they need to be formatted``( let result = fileFixture.Filename |> Seq.singleton - |> checkCode config + |> checkCode |> Async.RunSynchronously result.HasErrors |> should equal false diff --git a/src/Fantomas.Tests/CompilerDirectivesTests.fs b/src/Fantomas.Tests/CompilerDirectivesTests.fs index cdf001275b..184a8145be 100644 --- a/src/Fantomas.Tests/CompilerDirectivesTests.fs +++ b/src/Fantomas.Tests/CompilerDirectivesTests.fs @@ -1109,7 +1109,7 @@ type internal Close = | ProcessExit | Pause | Resume -""" ({ config with IndentSpaceNum = 2 }) +""" ({ config with IndentSize = 2 }) |> prepend newline |> should equal """ namespace AltCover.Recorder @@ -1144,7 +1144,7 @@ type internal Close = | ProcessExit | Pause | Resume -""" ({ config with IndentSpaceNum = 2 }) +""" ({ config with IndentSize = 2 }) |> prepend newline |> should equal """ namespace AltCover.Recorder @@ -1179,7 +1179,7 @@ type internal Close = | ProcessExit | Pause | Resume -""" ({ config with IndentSpaceNum = 2 }) +""" ({ config with IndentSize = 2 }) |> prepend newline |> should equal """ namespace AltCover.Recorder diff --git a/src/Fantomas.Tests/ComputationExpressionTests.fs b/src/Fantomas.Tests/ComputationExpressionTests.fs index df9f2afbd9..330dc592a4 100644 --- a/src/Fantomas.Tests/ComputationExpressionTests.fs +++ b/src/Fantomas.Tests/ComputationExpressionTests.fs @@ -1342,7 +1342,7 @@ let ``new line between let and let bang, 879`` () = } """ ({ config with SpaceBeforeUppercaseInvocation = true - IndentSpaceNum = 2 + IndentSize = 2 SpaceAroundDelimiter = false MultilineBlockBracketsOnSameColumn = true }) |> prepend newline diff --git a/src/Fantomas.Tests/ContextTests.fs b/src/Fantomas.Tests/ContextTests.fs index 7242b6ea36..5a9cebeb00 100644 --- a/src/Fantomas.Tests/ContextTests.fs +++ b/src/Fantomas.Tests/ContextTests.fs @@ -71,7 +71,7 @@ let ``nested exceedsMultiline expression should bubble up to parent check`` () = (sepNln +> !- "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +> sepNln +> !- "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +> sepNln) +> sepCloseA) - let config = { FormatConfig.Default with PageWidth = 50; SpaceAroundDelimiter = false } + let config = { FormatConfig.Default with MaxLineLength = 50; SpaceAroundDelimiter = false } let initialContext = { Context.Default with Config = config; } let result = dump (expression initialContext) diff --git a/src/Fantomas.Tests/ElmishTests.fs b/src/Fantomas.Tests/ElmishTests.fs index def8a996fd..6ad46a6313 100644 --- a/src/Fantomas.Tests/ElmishTests.fs +++ b/src/Fantomas.Tests/ElmishTests.fs @@ -495,7 +495,7 @@ let view (CurrentTime time) dispatch = SVG.Stroke "#023963" SVG.StrokeWidth 1.0 ] [] ] -""" { config with IndentSpaceNum = 2 } +""" { config with IndentSize = 2 } |> prepend newline |> should equal """ let view (CurrentTime time) dispatch = diff --git a/src/Fantomas.Tests/FSharpScriptTests.fs b/src/Fantomas.Tests/FSharpScriptTests.fs index 25e56ce51a..7235470059 100644 --- a/src/Fantomas.Tests/FSharpScriptTests.fs +++ b/src/Fantomas.Tests/FSharpScriptTests.fs @@ -27,7 +27,7 @@ let ``e2e script test with keyword __source__directory__`` () = let file = Path.Combine(Path.GetTempPath(), System.Guid.NewGuid().ToString("N") + ".fsx") File.WriteAllText(file, source) - let! formattedFiles = FakeHelpers.formatCode config [file] + let! formattedFiles = FakeHelpers.formatCode [file] let formattedSource = File.ReadAllText(file) Array.length formattedFiles == 1 @@ -54,13 +54,19 @@ let ``fantomas removes module and namespace if it is only 1 word`` () = let fantomasConfig = { FormatConfig.FormatConfig.Default with StrictMode = true - IndentSpaceNum = 2 + IndentSize = 2 SpaceBeforeColon = false } - let! formattedFiles = FakeHelpers.formatCode fantomasConfig [file] + |> EditorConfig.configToEditorConfig + + let editorConfigPath = Path.Combine(Path.GetTempPath(), ".editorconfig") + File.WriteAllText(editorConfigPath, fantomasConfig) + + let! formattedFiles = FakeHelpers.formatCode [file] let formattedSource = File.ReadAllText(file) Array.length formattedFiles == 1 File.Delete(file) + File.Delete(editorConfigPath) formattedSource |> String.normalizeNewLine @@ -84,7 +90,7 @@ let ``number in the filename should not end up in the module name`` () = File.WriteAllText(file, source) async { - let! formattedFiles = FakeHelpers.formatCode config [|file|] + let! formattedFiles = FakeHelpers.formatCode [|file|] let formattedSource = File.ReadAllText(file) Array.length formattedFiles == 1 File.Delete(file) diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 3232f1ef42..d0b4bf1d36 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -1,7 +1,7 @@ - 4.0.0-alpha-011 + 4.0.0-alpha-012 FS0988 netcoreapp3.1 @@ -56,7 +56,6 @@ - diff --git a/src/Fantomas.Tests/FormatConfigEditorConfigurationFileTests.fs b/src/Fantomas.Tests/FormatConfigEditorConfigurationFileTests.fs index 664100b772..73330f32d4 100644 --- a/src/Fantomas.Tests/FormatConfigEditorConfigurationFileTests.fs +++ b/src/Fantomas.Tests/FormatConfigEditorConfigurationFileTests.fs @@ -1,2 +1,177 @@ module Fantomas.Tests.FormatConfigEditorConfigurationFileTests +open System +open Fantomas +open Fantomas.FormatConfig +open NUnit.Framework +open System.IO +open Fantomas.Tests.TestHelper + +let private defaultConfig = FormatConfig.Default +let private tempName () = System.Guid.NewGuid().ToString("N") + +type ConfigurationFile internal (config: Fantomas.FormatConfig.FormatConfig, + ?editorConfigHeader: string, + ?subFolder: string, + ?isRoot: bool, + ?content: string) = + let editorConfigPath = + match subFolder with + | Some sf -> + let dirPath = Path.Join(Path.GetTempPath(), sf) + if not (Directory.Exists(dirPath)) + then Directory.CreateDirectory(dirPath) |> ignore + Path.Join(Path.GetTempPath(), sf, ".editorconfig") + | None -> Path.Join(Path.GetTempPath(), ".editorconfig") + + let header = + Option.defaultValue "[*.fs]" editorConfigHeader + + let content = + match content with + | Some c -> c + | None -> + let root = + match isRoot with + | Some true -> "root=true" + | _ -> String.empty + + sprintf "%s\n\n%s\n%s" root header (EditorConfig.configToEditorConfig config) + + do File.WriteAllText(editorConfigPath, content) + + interface IDisposable with + member this.Dispose(): unit = if File.Exists(editorConfigPath) then File.Delete(editorConfigPath) + +type FSharpFile internal (?fsharpFileExtension: string, ?subFolder: string) = + let extension = + Option.defaultValue ".fs" fsharpFileExtension + + let fsharpFile = sprintf "%s%s" (tempName ()) extension + + let fsharpFilePath = + match subFolder with + | Some sf -> + let dirPath = Path.Join(Path.GetTempPath(), sf) + if not (Directory.Exists(dirPath)) + then Directory.CreateDirectory(dirPath) |> ignore + Path.Join(Path.GetTempPath(), sf, fsharpFile) + | None -> Path.Join(Path.GetTempPath(), fsharpFile) + + do File.WriteAllText(fsharpFilePath, String.empty) + + member _.FSharpFile: string = fsharpFilePath + + interface IDisposable with + member this.Dispose(): unit = if File.Exists(fsharpFilePath) then File.Delete(fsharpFilePath) + +[] +let ``single configuration file`` () = + use configFixture = new ConfigurationFile(defaultConfig) + use fsharpFile = new FSharpFile(".fs") + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config == defaultConfig + +[] +let ``pointing to subfolder should return parent config file as well`` () = + let subFolder = tempName () + + use parentConfig = + new ConfigurationFile({ defaultConfig with IndentSize = 3 }) + + use childConfig = + new ConfigurationFile({ defaultConfig with IndentSize = 2 }, subFolder = subFolder) + + use fsharpFile = new FSharpFile(subFolder = subFolder) + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config.IndentSize == 2 + +[] +let ``parent config should not be taking into account when child is root`` () = + let subFolder = tempName () + + use parentConfig = + new ConfigurationFile({ defaultConfig with + MaxRecordWidth = 10 }) + + use childConfig = + new ConfigurationFile({ defaultConfig with IndentSize = 2 }, subFolder = subFolder, isRoot = true) + + use fsharpFile = new FSharpFile(subFolder = subFolder) + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config.MaxRecordWidth + == defaultConfig.MaxRecordWidth + config.IndentSize == 2 + +[] +let ``configuration file should not affect file extension`` () = + use configFixture = + new ConfigurationFile({ defaultConfig with + MaxLineLength = 90 }) + + use fsharpFile = new FSharpFile(".fsx") + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config.MaxLineLength + == defaultConfig.MaxLineLength + +[] +let ``fantomas-tool configuration file`` () = + let myConfig = """ +[*.fs] +fsharp_max_if_then_else_short_width=25 +fsharp_max_value_binding_width=40 +fsharp_max_function_binding_width=40 +""" + + use configFixture = + new ConfigurationFile(defaultConfig, content = myConfig) + + use fsharpFile = new FSharpFile() + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config.MaxIfThenElseShortWidth == 25 + config.MaxValueBindingWidth == 40 + config.MaxFunctionBindingWidth == 40 + +[] +let ``non existing file should return default config`` () = + use configFixture = new ConfigurationFile(defaultConfig) + + let config = + CodeFormatter.ReadConfiguration "bogus.fs" + + config == defaultConfig + +[] +let ``indent_style tab edge case`` () = + let editorConfig = """ +[*.fs] +indent_style=tab +indent_size=tab +tab_width=5 +fsharp_indent_on_try_with=true +""" + + use configFixture = + new ConfigurationFile(defaultConfig, content = editorConfig) + + use fsharpFile = new FSharpFile() + + let config = + CodeFormatter.ReadConfiguration fsharpFile.FSharpFile + + config.IndentSize == 5 diff --git a/src/Fantomas.Tests/FormatConfigJsonConfigurationFileTests.fs b/src/Fantomas.Tests/FormatConfigJsonConfigurationFileTests.fs deleted file mode 100644 index 2fdd0edd69..0000000000 --- a/src/Fantomas.Tests/FormatConfigJsonConfigurationFileTests.fs +++ /dev/null @@ -1,186 +0,0 @@ -module Fantomas.Tests.FormatConfigJsonConfigurationFileTests - -open Fantomas -open Fantomas.FormatConfig -open NUnit.Framework -open System.IO -open Fantomas.Tests.TestHelper - -[] -let private ConfigFileName = "fantomas-config.json" - -let private mkConfig subFolder config = - let json = Config.configToJson config - mkConfigFromContent ConfigFileName subFolder json - -let private mkConfigFromJson subFolder json = - mkConfigFromContent ConfigFileName subFolder json - -let rec private delete fileOrFolder = - if File.Exists(fileOrFolder) then - File.Delete fileOrFolder - else if Directory.Exists fileOrFolder then - Directory.EnumerateFiles fileOrFolder - |> Seq.iter delete - Directory.Delete fileOrFolder - else - () -let private uniqueString () = System.Guid.NewGuid().ToString("N") - -let private applyOptionsToConfig config path = - let json = File.ReadAllText path - let options, warnings = JsonConfig.parseOptionsFromJson json - FormatConfig.ApplyOptions(config, options),warnings - -[] -let ``single configuration file`` () = - let file = mkConfig None FormatConfig.Default - try - let paths = ConfigFile.findConfigurationFiles file - paths == [file] - finally - delete file - -[] -let ``folder with configuration file`` () = - let file = mkConfig None FormatConfig.Default - let folder = Path.GetDirectoryName(file) - try - let paths = ConfigFile.findConfigurationFiles folder - paths == [file] - finally - delete file - -[] -let ``pointing to subfolder should return parent config file as well`` () = - let parentFile = mkConfig None FormatConfig.Default - let childFile = mkConfig (Some(uniqueString())) FormatConfig.Default - let childFolder = Path.GetDirectoryName(childFile) - try - let paths = ConfigFile.findConfigurationFiles childFolder - paths == [parentFile; childFile] - finally - delete parentFile - delete childFolder - -[] -let ``pointing to config in a subfolder should return parent config file as well`` () = - let parentFile = mkConfig None FormatConfig.Default - let childFile = mkConfig (Some(uniqueString())) FormatConfig.Default - let childFolder = Path.GetDirectoryName(childFile) - try - let paths = ConfigFile.findConfigurationFiles childFile - paths == [parentFile; childFile] - finally - delete parentFile - delete childFolder - -[] -let ``pointing to subfolder containing dot and trailing slash returns parent config file`` () = - let parentFile = mkConfig None FormatConfig.Default - let subDir = uniqueString() + ".dir" - mkConfigFromContent "Test.fs" (Some(subDir)) "" |> ignore - let dirSep = string Path.DirectorySeparatorChar - let childFolder = Path.GetDirectoryName(parentFile) + dirSep + subDir + dirSep - try - let paths = ConfigFile.findConfigurationFiles childFolder - paths == [parentFile] - finally - delete parentFile - delete childFolder - -[] -let ``pointing to subfolder conntaining dot without trailing slash returns parent config file`` () = - let parentFile = mkConfig None FormatConfig.Default - let subDir = uniqueString() + ".dir" - mkConfigFromContent "Test.fs" (Some(subDir)) "" |> ignore - let dirSep = string Path.DirectorySeparatorChar - let childFolder = Path.GetDirectoryName(parentFile) + dirSep + subDir - try - let paths = ConfigFile.findConfigurationFiles childFolder - paths == [parentFile] - finally - delete parentFile - delete childFolder - -[] -let ``simple config file parses valid option`` () = - let path = mkConfigFromJson None "{\"IndentOnTryWith\":true}" - let config, warnings = applyOptionsToConfig FormatConfig.Default path - true == config.IndentOnTryWith - [] == warnings - -[] -let ``keys should not necessarily have quotes to be parsed`` () = - let path = mkConfigFromJson None "{IndentOnTryWith:true}" - let config, warnings = applyOptionsToConfig FormatConfig.Default path - true == config.IndentOnTryWith - [] == warnings - -[] -let ``invalid option returns a warning`` () = - let path = mkConfigFromJson None "{ \"Foo\": true }" - let config, warnings = applyOptionsToConfig FormatConfig.Default path - config == FormatConfig.Default - match warnings with - | [| error |] -> - StringAssert.IsMatch("\"Foo\":true is no valid setting for Fantomas v(.*)", error) - | _ -> fail() - -[] -let ``non existing file should return an error`` () = - let path = Path.Combine(Path.GetTempPath(), uniqueString()) - let result = CodeFormatter.ReadConfiguration path - match result with - | Failure f -> - (sprintf "No configuration files were found for %s" path) == f.Message - | _ -> fail() - -[] -let ``child configuration should overwrite parent folder`` () = - let parentConfig = mkConfigFromJson None "{\"PageWidth\": 70}" - let childConfig = mkConfigFromJson (Some(uniqueString())) "{\"PageWidth\": 90}" - let childFolder = Path.GetDirectoryName(childConfig) - - try - let result = CodeFormatter.ReadConfiguration childConfig - match result with - | Success config -> 90 == config.PageWidth - | _ -> fail() - finally - delete parentConfig - delete childFolder - -[] -let ``invalid key in parent config should return partial success`` () = - let parentConfig = mkConfigFromJson None "{\"PageWidthX\": 70}" - let childConfig = mkConfigFromJson (Some(uniqueString())) "{\"PageWidth\": 130}" - let childFolder = Path.GetDirectoryName(childConfig) - - try - let result = CodeFormatter.ReadConfiguration childConfig - match result with - | PartialSuccess (config, [warning]) -> - 130 == config.PageWidth - let pieces = warning.Split([|','|]) - StringAssert.Contains("\"PageWidthX\"", pieces.[0]) - StringAssert.Contains(parentConfig, pieces.[1]) - | _ -> fail() - finally - delete parentConfig - delete childFolder - -[] -let ``$schema key should not return warning`` () = - let path = mkConfigFromJson None """ -{ - "$schema": "http://json.schemastore.org/fantomas", - "PageWidth": 99, - "IndentSpaceNum": 2, - "IndentOnTryWith": true -} -""" - let _, warnings = - File.ReadAllText path - |> JsonConfig.parseOptionsFromJson - [] == warnings \ No newline at end of file diff --git a/src/Fantomas.Tests/FunctionDefinitionTests.fs b/src/Fantomas.Tests/FunctionDefinitionTests.fs index 0c7a845d67..3d12f230d0 100644 --- a/src/Fantomas.Tests/FunctionDefinitionTests.fs +++ b/src/Fantomas.Tests/FunctionDefinitionTests.fs @@ -379,7 +379,7 @@ let fold (funcs : ResultFunc<'Input, 'Output, 'TError> seq) (input : 'Input) : R | true -> Error collectedErrors | false -> Ok collectedOutputs """ ({ config with - PageWidth = 100 + MaxLineLength = 100 SpaceBeforeColon = true MaxInfixOperatorExpression = 70 }) |> prepend newline @@ -427,7 +427,7 @@ let ``internal keyword included in function signature length check`` () = let UpdateStrongNamingX (assembly : AssemblyDefinition) (key : StrongNameKeyPair option) = assembly.Name -""" ({ config with PageWidth = 90; SpaceBeforeColon = true }) +""" ({ config with MaxLineLength = 90; SpaceBeforeColon = true }) |> prepend newline |> should equal """ let internal UpdateStrongNaming @@ -523,7 +523,7 @@ let private addTaskToScheduler (scheduler : IScheduler) taskName taskCron prio ( JobBuilder.Create().UsingJobData(jobDataMap) .WithIdentity(taskName, groupName).Build() 1 -""" ({ config with PageWidth = 100 }) +""" ({ config with MaxLineLength = 100 }) |> prepend newline |> should equal """ let private addTaskToScheduler @@ -548,7 +548,7 @@ let private addTaskToScheduler 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 } +""" { config with IndentSize = 2; SpaceBeforeColon = true } |> prepend newline |> should equal """ let readModel @@ -563,7 +563,7 @@ let readModel 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 } +""" { config with IndentSize = 2; SpaceBeforeColon = true; MaxLineLength = 80 } |> prepend newline |> should equal """ let readModel diff --git a/src/Fantomas.Tests/IfThenElseTests.fs b/src/Fantomas.Tests/IfThenElseTests.fs index 066b7945ac..561e232ebc 100644 --- a/src/Fantomas.Tests/IfThenElseTests.fs +++ b/src/Fantomas.Tests/IfThenElseTests.fs @@ -90,7 +90,7 @@ else g [] let ``longer condition, not multi-line`` () = formatSourceString false """if aaaaaaaaaBBBBBBBBBBccccccccccDDDDDDDDDeeeeeeeeeeeeeFFFFFFFFFFFggggggggg then 1 else 0 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if aaaaaaaaaBBBBBBBBBBccccccccccDDDDDDDDDeeeeeeeeeeeeeFFFFFFFFFFFggggggggg @@ -101,7 +101,7 @@ else 0 [] let ``longer ifBranch, not multi-line`` () = formatSourceString false """if x then aaaaaaaaaBBBBBBBBBBccccccccccDDDDDDDDDeeeeeeeeeeeeeFFFFFFFFFFFggggggggg else 0 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if x @@ -112,7 +112,7 @@ else 0 [] let ``longer else branch, not multi-line`` () = formatSourceString false """if x then 1 else aaaaaaaaaBBBBBBBBBBccccccccccDDDDDDDDDeeeeeeeeeeeeeFFFFFFFFFFFggggggggg -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if x @@ -123,7 +123,7 @@ else aaaaaaaaaBBBBBBBBBBccccccccccDDDDDDDDDeeeeeeeeeeeeeFFFFFFFFFFFggggggggg [] let ``longer if else branch, not multi-line`` () = formatSourceString false """if aaaaaaaaaaaa then bbbbbbbbbbbb else if cccccccccccc then ddddddddddd else eeeeeee -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if aaaaaaaaaaaa then bbbbbbbbbbbb @@ -134,7 +134,7 @@ else eeeeeee [] let ``longer if else branch, longer elif branch, not multi-line`` () = formatSourceString false """if aaaaaa then bbbbbb else if ccccccc then ddddddd elif eeeee then ffffff else gggggg -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if aaaaaa then bbbbbb @@ -147,7 +147,7 @@ else gggggg let ``multiline condition`` () = formatSourceString false """if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) then x else y -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -163,7 +163,7 @@ let ``multiline if branch`` () = let x = 2 x + 2 else y -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if a then @@ -180,7 +180,7 @@ let ``multiline else branch`` () = else let y = 7; y + 9 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if a then @@ -198,7 +198,7 @@ let ``multiline else if branch`` () = y + 9 else 99 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if a then @@ -221,7 +221,7 @@ let ``multiline else if branch, multiline elif branch`` () = z - 7 else 99 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if a then @@ -721,7 +721,7 @@ let ``simple if/else with long identifiers`` () = if someveryveryveryverylongexpression then someveryveryveryveryveryverylongexpression else someveryveryveryverylongexpression -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ if someveryveryveryverylongexpression diff --git a/src/Fantomas.Tests/InterfaceTests.fs b/src/Fantomas.Tests/InterfaceTests.fs index 9a8b563587..13c6e579ef 100644 --- a/src/Fantomas.Tests/InterfaceTests.fs +++ b/src/Fantomas.Tests/InterfaceTests.fs @@ -150,7 +150,7 @@ type MyLogInteface() = else sprintf "date-%s.log" environment member x.Info () = () - override x.Version () = ()""" ({ config with PageWidth = 119; MaxFunctionBindingWidth = 120 }) + override x.Version () = ()""" ({ config with MaxLineLength = 119; MaxFunctionBindingWidth = 120 }) |> prepend newline |> should equal """ type LogInterface = diff --git a/src/Fantomas.Tests/KeepIfThenInSameLineTests.fs b/src/Fantomas.Tests/KeepIfThenInSameLineTests.fs index bf2828a4ea..31fdc0ee8a 100644 --- a/src/Fantomas.Tests/KeepIfThenInSameLineTests.fs +++ b/src/Fantomas.Tests/KeepIfThenInSameLineTests.fs @@ -6,7 +6,7 @@ open Fantomas.Tests.TestHelper let config = { config with KeepIfThenInSameLine = true - PageWidth = 80 + MaxLineLength = 80 MaxIfThenElseShortWidth = 0 } [] @@ -18,7 +18,7 @@ let ``if only, 825`` () = "some very very long error message" if valueToSend <= 0m then invalidArg "valueToSend" "Amount has to be above zero" -""" { config with PageWidth = 100 } +""" { config with MaxLineLength = 100 } |> prepend newline |> should equal """ type TransferAmount(valueToSend: decimal, balanceAtTheMomentOfSending: decimal) = diff --git a/src/Fantomas.Tests/LambdaTests.fs b/src/Fantomas.Tests/LambdaTests.fs index a4f771a55f..d454d44f32 100644 --- a/src/Fantomas.Tests/LambdaTests.fs +++ b/src/Fantomas.Tests/LambdaTests.fs @@ -8,7 +8,7 @@ open Fantomas.Tests.TestHelper let ``keep comment after arrow`` () = formatSourceString false """_Target "FSharpTypesDotNet" (fun _ -> // obsolete ()) -""" ({ config with IndentSpaceNum = 2; PageWidth = 90 }) +""" ({ config with IndentSize = 2; MaxLineLength = 90 }) |> prepend newline |> should equal """ _Target "FSharpTypesDotNet" (fun _ -> // obsolete @@ -88,7 +88,7 @@ let a = b |> List.exists (fun p -> x && someVeryLongIdentifierrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrzzzz___________) -""" ({ config with PageWidth = 80}) +""" ({ config with MaxLineLength = 80}) |> prepend newline |> should equal """ let a = @@ -180,7 +180,7 @@ let ``short ident in nested let binding`` () = foo (fun a -> let b = 8 b) -""" ({ config with IndentSpaceNum = 2}) +""" ({ config with IndentSize = 2}) |> prepend newline |> should equal """ let a = @@ -335,7 +335,7 @@ let projectIntoMap projection = |> Map.add eventEnvelope.Metadata.Source newState """ ({ config with - IndentSpaceNum = 2 + IndentSize = 2 SpaceBeforeUppercaseInvocation = true SpaceBeforeColon = true SpaceAfterComma = false diff --git a/src/Fantomas.Tests/ListTests.fs b/src/Fantomas.Tests/ListTests.fs index 4f417b394b..2e9cf65e02 100644 --- a/src/Fantomas.Tests/ListTests.fs +++ b/src/Fantomas.Tests/ListTests.fs @@ -190,7 +190,7 @@ let ``multiline list of string should not add ;`` () = formatSourceString false """ [ "_Binaries/AltCover/Debug+AnyCPU/AltCover.exe" "_Binaries/AltCover.Shadow/Debug+AnyCPU/AltCover.Shadow.dll" ] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> should equal """[ "_Binaries/AltCover/Debug+AnyCPU/AltCover.exe" "_Binaries/AltCover.Shadow/Debug+AnyCPU/AltCover.Shadow.dll" ] """ @@ -1407,7 +1407,7 @@ let nestedList: obj list = [ "33333333bbbbbbbbbbbbbbb" ] ] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let nestedList: obj list = @@ -1434,7 +1434,7 @@ let nestedList: obj list = [| "33333333bbbbbbbbbbbbbbb" |] |] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let nestedList: obj list = @@ -1460,7 +1460,7 @@ let nestedList: obj list = [| "33333333bbbbbbbbbbbbbbb" |] |] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let nestedList: obj list = @@ -1487,7 +1487,7 @@ let nestedList: obj list = [ // this case looks weird but seen rarely ] ] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let nestedList: obj list = @@ -1515,7 +1515,7 @@ let nestedList: obj list = [| // this case looks weird but seen rarely |] |] -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let nestedList: obj list = @@ -1538,7 +1538,7 @@ let c = list.[0..^1] // 1,2,3,4 let d = list.[^1..] // 4,5 let e = list.[^0..] // 5 let f = list.[^2..^1] // 3,4 -""" ({ config with PageWidth = 80 }) +""" ({ config with MaxLineLength = 80 }) |> prepend newline |> should equal """ let a = list.[..^0] // 1,2,3,4,5 diff --git a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs index 2ad50f6fe7..8d5e76cafc 100644 --- a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs +++ b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs @@ -578,7 +578,7 @@ type A = [] let ``indent update record fields far enough, 817`` () = - formatSourceString false "let expected = { ThisIsAThing.Empty with TheNewValue = 1 }" ({ config with IndentSpaceNum = 2 }) + formatSourceString false "let expected = { ThisIsAThing.Empty with TheNewValue = 1 }" ({ config with IndentSize = 2 }) |> prepend newline |> should equal """ let expected = @@ -589,7 +589,7 @@ let expected = [] let ``indent update anonymous record fields far enough`` () = - formatSourceString false "let expected = {| ThisIsAThing.Empty with TheNewValue = 1 |}" ({ config with IndentSpaceNum = 2 }) + formatSourceString false "let expected = {| ThisIsAThing.Empty with TheNewValue = 1 |}" ({ config with IndentSize = 2 }) |> prepend newline |> should equal """ let expected = diff --git a/src/Fantomas.Tests/OperatorTests.fs b/src/Fantomas.Tests/OperatorTests.fs index 1c0c6319a0..6a14890e4d 100644 --- a/src/Fantomas.Tests/OperatorTests.fs +++ b/src/Fantomas.Tests/OperatorTests.fs @@ -91,7 +91,7 @@ let ``should pattern match on quotation expression``() = let ``should break on . operator``() = formatSourceString false """pattern.Replace(".", @"\.").Replace("$", @"\$").Replace("^", @"\^").Replace("{", @"\{").Replace("[", @"\[").Replace("(", @"\(").Replace(")", @"\)").Replace("+", @"\+") - """ { config with PageWidth = 80 } + """ { config with MaxLineLength = 80 } |> prepend newline |> should equal """ pattern.Replace(".", @"\.").Replace("$", @"\$").Replace("^", @"\^") @@ -106,7 +106,7 @@ let ``should break on . operator and keep indentation``() = (x + y) .Replace(seperator + "**" + seperator, replacementSeparator + "(.|?" + replacementSeparator + ")?" ) .Replace("**" + seperator, ".|(?<=^|" + replacementSeparator + ")" ) - """ { config with PageWidth = 80; MaxInfixOperatorExpression = 60 } + """ { config with MaxLineLength = 80; MaxInfixOperatorExpression = 60 } |> should equal """let pattern = (x + y) .Replace diff --git a/src/Fantomas.Tests/PatternMatchingTests.fs b/src/Fantomas.Tests/PatternMatchingTests.fs index a4fd054507..7b5079f4fb 100644 --- a/src/Fantomas.Tests/PatternMatchingTests.fs +++ b/src/Fantomas.Tests/PatternMatchingTests.fs @@ -194,7 +194,7 @@ try fst(find (fun (s, (s', ty): int * int) -> s' = s0 && can (type_match ty ty0) []) (!the_interface)) with -| Failure _ -> s0""" { config with PageWidth = 80 } +| Failure _ -> s0""" { config with MaxLineLength = 80 } |> prepend newline |> should equal """ try @@ -384,7 +384,7 @@ let (|OneLinerBinding|MultilineBinding|) b = [] let ``should split constructor and function call correctly, double formatting`` () = - let config80 = { config with PageWidth = 80 } + let config80 = { config with MaxLineLength = 80 } let original = """ let update msg model = @@ -458,7 +458,7 @@ match x with let z = 1 Some(y + z) | None -> None -""" { config with IndentSpaceNum = 2 } +""" { config with IndentSize = 2 } |> prepend newline |> should equal """ match x with diff --git a/src/Fantomas.Tests/PipingTests.fs b/src/Fantomas.Tests/PipingTests.fs index 1ebbe0705f..d06a26fb04 100644 --- a/src/Fantomas.Tests/PipingTests.fs +++ b/src/Fantomas.Tests/PipingTests.fs @@ -13,7 +13,7 @@ let f x = <|> if someveryveryveryverylongexpression then someveryveryveryverylongexpression else someveryveryveryverylongexpression <|> if someveryveryveryverylongexpression then someveryveryveryverylongexpression else someveryveryveryverylongexpression |> f - """ { config with PageWidth = 80 } + """ { config with MaxLineLength = 80 } |> prepend newline |> should equal """ let f x = diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index 738daf7120..c91ef7aece 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -782,7 +782,7 @@ let x = (Label = "Test", IntrinsicSettings = JobCollectionIntrinsicSettings (Plan = JobCollectionPlan.Standard, - Quota = new JobCollectionQuota(MaxJobCount = Nullable(50))))""" { config with PageWidth = 120 } + Quota = new JobCollectionQuota(MaxJobCount = Nullable(50))))""" { config with MaxLineLength = 120 } |> prepend newline |> should equal """ let x = @@ -1119,7 +1119,7 @@ let ``keep correct indentation after multiline member definition, 845`` () = member SomeOtherMember () = printfn "b" -""" ({ config with PageWidth = 80; MaxFunctionBindingWidth = 120 }) +""" ({ config with MaxLineLength = 80; MaxFunctionBindingWidth = 120 }) |> prepend newline |> should equal """ type SomeType() = @@ -1140,7 +1140,7 @@ let ``keep correct indentation after multiline typed member definition`` () = member SomeOtherMember () = printfn "b" -""" ({ config with PageWidth = 80; MaxFunctionBindingWidth = 120 }) +""" ({ config with MaxLineLength = 80; MaxFunctionBindingWidth = 120 }) |> prepend newline |> should equal """ type SomeType() = @@ -1275,7 +1275,7 @@ let ``long type members should be in multiple lines, 868`` () = type C() = member _.LongMethodWithLotsOfParameters(aVeryLongType: int, aSecondVeryLongType: int, aThirdVeryLongType: int) : int = aVeryLongType + aSecondVeryLongType + aThirdVeryLongType -""" { config with PageWidth = 80; SpaceBeforeColon = true; MaxInfixOperatorExpression = 80 } +""" { config with MaxLineLength = 80; SpaceBeforeColon = true; MaxInfixOperatorExpression = 80 } |> prepend newline |> should equal """ type C() = @@ -1292,7 +1292,7 @@ let ``long type members should be in multiple lines, no return type`` () = type C() = member _.LongMethodWithLotsOfParameters(aVeryLongType: int, aSecondVeryLongType: int, aThirdVeryLongType: int) = aVeryLongType + aSecondVeryLongType + aThirdVeryLongType -""" { config with PageWidth = 80; SpaceBeforeColon = true; MaxInfixOperatorExpression = 80 } +""" { config with MaxLineLength = 80; SpaceBeforeColon = true; MaxInfixOperatorExpression = 80 } |> prepend newline |> should equal """ type C() = @@ -1307,7 +1307,7 @@ let ``long type constructors should be in multiple lines, 868`` () = formatSourceString false """ type VersionMismatchDuringDeserializationException(message: string, innerException: System.Exception) = inherit System.Exception(message, innerException) -""" { config with PageWidth = 80; SpaceBeforeColon = true } +""" { config with MaxLineLength = 80; SpaceBeforeColon = true } |> prepend newline |> should equal """ type VersionMismatchDuringDeserializationException(message : string, diff --git a/src/Fantomas/CodeFormatter.fs b/src/Fantomas/CodeFormatter.fs index 4d9bc4fe73..af0f194326 100644 --- a/src/Fantomas/CodeFormatter.fs +++ b/src/Fantomas/CodeFormatter.fs @@ -34,4 +34,4 @@ type CodeFormatter = static member GetVersion() = Version.fantomasVersion.Value - static member ReadConfiguration(fileOrFolder) = CodeFormatterImpl.readConfiguration fileOrFolder + static member ReadConfiguration(fsharpFile) = CodeFormatterImpl.readConfiguration fsharpFile diff --git a/src/Fantomas/CodeFormatter.fsi b/src/Fantomas/CodeFormatter.fsi index 266d3b53d6..c052b6a0fb 100644 --- a/src/Fantomas/CodeFormatter.fsi +++ b/src/Fantomas/CodeFormatter.fsi @@ -34,6 +34,5 @@ type CodeFormatter = /// Returns the version of Fantomas found in the AssemblyInfo static member GetVersion : unit -> string - /// Accepts a file or a folder and parses the found json to a FormatConfig - /// Configuration found in parent folders will be applied first. - static member ReadConfiguration : string -> FormatConfigFileParseResult + /// Accepts a fsharp file and parses the matching .editorconfig to a FormatConfig + static member ReadConfiguration : string -> FormatConfig diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index c4177b900b..3273011128 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -673,34 +673,8 @@ type internal BlockType = /// Make a position at (line, col) to denote cursor position let makePos line col = mkPos line col -let readConfiguration fileOrFolder = - try - let configurationFiles = - ConfigFile.findConfigurationFiles fileOrFolder - - if List.isEmpty configurationFiles then failwithf "No configuration files were found for %s" fileOrFolder - - let (config,warnings) = - List.fold (fun (currentConfig, warnings) configPath -> - let configContent = System.IO.File.ReadAllText(configPath) - let options, warningFromConfigPath = - match System.IO.Path.GetFileName(configPath) with - | json when (json = ConfigFile.jsonConfigFileName) -> - JsonConfig.parseOptionsFromJson configContent - | editorconfig when (editorconfig = ConfigFile.editorConfigFileName) -> - EditorConfig.parseOptionsFromEditorConfig configContent - | _ -> - failwithf "Filename is not supported!" - let updatedConfig = FormatConfig.ApplyOptions(currentConfig, options) - let locationAwareWarnings = - List.ofArray warningFromConfigPath - |> List.map (ConfigFile.makeWarningLocationAware configPath) - - (updatedConfig, warnings @ locationAwareWarnings) - ) (FormatConfig.Default, []) configurationFiles - - match warnings with - | [] -> FormatConfigFileParseResult.Success config - | w -> FormatConfigFileParseResult.PartialSuccess (config, w) - with - | exn -> FormatConfigFileParseResult.Failure exn +let private editorConfigParser = Fantomas.EditorConfig.Core.EditorConfigParser() + +let readConfiguration (fsharpFile:string) : FormatConfig = + let editorConfigSettings: Fantomas.EditorConfig.Core.FileConfiguration = editorConfigParser.Parse(fileName = fsharpFile) + EditorConfig.parseOptionsFromEditorConfig editorConfigSettings \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index a91b087b98..e67b1f1347 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -465,7 +465,7 @@ and genExprSepEqPrependType astContext (pat:SynPat) (e: SynExpr) (valInfo:SynVal fun ctx -> let alreadyHasNewline = lastWriteEventIsNewline ctx if alreadyHasNewline then - (rep ctx.Config.IndentSpaceNum (!- " ") +> !- "=") ctx + (rep ctx.Config.IndentSize (!- " ") +> !- "=") ctx else (indent +> sepNln +> !- "=" +> unindent) ctx else @@ -2931,7 +2931,7 @@ and genPatWithReturnType ao s ps tpso (t:SynType option) (astContext: ASTContext + lengthWhenSome (fun _ -> colon) t + lengthWhenSome getSynTypeLength t - (ctx.Column + lengthByAST > ctx.Config.PageWidth) + (ctx.Column + lengthByAST > ctx.Config.MaxLineLength) || futureNlnCheck (genName +> genParametersInitial +> genReturnType) ctx fun ctx -> diff --git a/src/Fantomas/ConfigFile.fs b/src/Fantomas/ConfigFile.fs deleted file mode 100644 index cc92bc383d..0000000000 --- a/src/Fantomas/ConfigFile.fs +++ /dev/null @@ -1,69 +0,0 @@ -module internal Fantomas.ConfigFile - -open System -open System.IO -open Fantomas.FormatConfig -open Fantomas.Version - -let jsonConfigFileName = "fantomas-config.json" -let editorConfigFileName = ".editor-config" - -let private allowedFileNames = [jsonConfigFileName; editorConfigFileName] - -let rec private getParentFolders acc current = - let parent = Directory.GetParent(current) |> Option.ofObj - match parent with - | Some p -> getParentFolders (current::acc) p.FullName - | None -> current::acc - -/// Returns all the found configuration files for the given path -/// fileOrFolder can be a concrete json file or a directory path -let rec findConfigurationFiles fileOrFolder : string list = - let findConfigInFolder folderPath = - allowedFileNames - |> List.map (fun fn -> Path.Combine(folderPath, fn)) - |> List.filter (File.Exists) - - if Directory.Exists fileOrFolder then - getParentFolders [] fileOrFolder - |> List.collect findConfigInFolder - elif File.Exists(fileOrFolder) then - let parentFolder = - if String.IsNullOrWhiteSpace(Path.GetDirectoryName(fileOrFolder)) then - Directory.GetCurrentDirectory() - |> DirectoryInfo - |> Some - else - Directory.GetParent(Path.GetDirectoryName(fileOrFolder)) - |> Option.ofObj - - match parentFolder with - | Some pf -> findConfigurationFiles pf.FullName @ [fileOrFolder] - | None -> [fileOrFolder] - else - [] - -let makeWarningLocationAware configPath warning = - sprintf "%s, in %s" warning configPath - -let private fantomasFields = Reflection.getRecordFields FormatConfig.Default |> Array.map fst -let private (|FantomasSetting|_|) (s:string) = - let s = s.Trim('\"') - Array.tryFind ((=) s) fantomasFields - -let private (|Number|_|) d = - match System.Int32.TryParse(d) with - | true, d -> Some (box d) - | _ -> None -let private (|Boolean|_|) b = - if b = "true" then Some (box true) - elif b = "false" then Some (box false) - else None - -let processSetting originalLine key value = - match (key, value) with - | (FantomasSetting(fs), Number(v)) - | (FantomasSetting(fs), Boolean(v)) -> Ok (fs, v) - | _ -> - let warning = sprintf "%s is no valid setting for Fantomas v%s" originalLine (fantomasVersion.Value) - Error warning \ No newline at end of file diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index c99267636c..657a610e31 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -163,7 +163,7 @@ type internal Context = let keepPageWidth = keepPageWidth |> Option.defaultValue false let mkModel m = { m with Mode = Dummy; Lines = [String.replicate x.WriterModel.Column " "]; WriteBeforeNewline = "" } // Use infinite column width to encounter worst-case scenario - let config = { x.Config with PageWidth = if keepPageWidth then x.Config.PageWidth else Int32.MaxValue } + let config = { x.Config with MaxLineLength = if keepPageWidth then x.Config.MaxLineLength else Int32.MaxValue } { x with WriterModel = mkModel x.WriterModel; WriterEvents = writerCommands; Config = config } member x.WithShortExpression(maxWidth, ?startColumn) = @@ -185,7 +185,7 @@ let internal writerEvent e ctx = let ctx' = { ctx with WriterEvents = Queue.append ctx.WriterEvents evs - WriterModel = (ctx.WriterModel, evs) ||> Seq.fold (fun m e -> WriterModel.update ctx.Config.PageWidth e m) } + WriterModel = (ctx.WriterModel, evs) ||> Seq.fold (fun m e -> WriterModel.update ctx.Config.MaxLineLength e m) } ctx' let internal finalizeWriterModel (ctx: Context) = if ctx.WriterModel.WriteBeforeNewline <> "" then writerEvent (Write ctx.WriterModel.WriteBeforeNewline) ctx else ctx @@ -250,11 +250,11 @@ let internal forallCharsOnLastLine f ctx = /// Indent one more level based on configuration let internal indent (ctx : Context) = // if atColumn is bigger then after indent, then we use atColumn as base for indent - writerEvent (IndentBy ctx.Config.IndentSpaceNum) ctx + writerEvent (IndentBy ctx.Config.IndentSize) ctx /// Unindent one more level based on configuration let internal unindent (ctx : Context) = - writerEvent (UnIndentBy ctx.Config.IndentSpaceNum) ctx + writerEvent (UnIndentBy ctx.Config.IndentSize) ctx /// Increase indent by i spaces let internal incrIndent i (ctx : Context) = @@ -431,7 +431,7 @@ let internal onlyIfNot cond f ctx = if cond then ctx else f ctx let internal whenShortIndent f ctx = - onlyIf (ctx.Config.IndentSpaceNum < 3) f ctx + onlyIf (ctx.Config.IndentSize < 3) f ctx /// Repeat application of a function n times let internal rep n (f : Context -> Context) (ctx : Context) = @@ -534,7 +534,7 @@ let private shortExpressionWithFallback (shortExpression: Context -> Context) (f // if the context is already inside a ShortExpression mode and tries to figure out if the expression will go over the page width, // we should try the shortExpression in this case. match ctx.WriterModel.Mode with - | ShortExpression infos when (List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.PageWidth ctx.Column) infos) -> + | ShortExpression infos when (List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.MaxLineLength ctx.Column) infos) -> ctx | _ -> // create special context that will process the writer events slightly different @@ -547,7 +547,7 @@ let private shortExpressionWithFallback (shortExpression: Context -> Context) (f match resultContext.WriterModel.Mode with | ShortExpression infos -> // verify the expression is not longer than allowed - if List.exists(fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.PageWidth resultContext.Column) infos + if List.exists(fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.MaxLineLength resultContext.Column) infos then fallbackExpression ctx else { resultContext with WriterModel = { resultContext.WriterModel with Mode = ctx.WriterModel.Mode } } @@ -562,7 +562,7 @@ let internal isShortExpressionOrAddIndentAndNewline maxWidth expr (ctx: Context) shortExpressionWithFallback expr (indent +> sepNln +> expr +> unindent) maxWidth None ctx let internal expressionFitsOnRestOfLine expression fallbackExpression (ctx: Context) = - shortExpressionWithFallback expression fallbackExpression ctx.Config.PageWidth (Some 0) ctx + shortExpressionWithFallback expression fallbackExpression ctx.Config.MaxLineLength (Some 0) ctx /// provide the line and column before and after the leadingExpression to to the continuation expression let internal leadingExpressionResult leadingExpression continuationExpression (ctx: Context) = @@ -588,20 +588,20 @@ let internal leadingExpressionIsMultiline leadingExpression continuationExpressi let private expressionExceedsPageWidth beforeShort afterShort beforeLong afterLong expr (ctx: Context) = // if the context is already inside a ShortExpression mode, we should try the shortExpression in this case. match ctx.WriterModel.Mode with - | ShortExpression infos when (List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.PageWidth ctx.Column) infos) -> + | ShortExpression infos when (List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.MaxLineLength ctx.Column) infos) -> ctx | ShortExpression _ -> // if the context is already inside a ShortExpression mode, we should try the shortExpression in this case. (beforeShort +> expr +> afterShort) ctx | _ -> - let shortExpressionContext = ctx.WithShortExpression(ctx.Config.PageWidth, 0) + let shortExpressionContext = ctx.WithShortExpression(ctx.Config.MaxLineLength, 0) let resultContext = (beforeShort +> expr +> afterShort) shortExpressionContext let fallbackExpression = beforeLong +> expr +> afterLong match resultContext.WriterModel.Mode with | ShortExpression infos -> // verify the expression is not longer than allowed - if List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.PageWidth resultContext.Column) infos then + if List.exists (fun info -> info.ConfirmedMultiline || info.IsTooLong ctx.Config.MaxLineLength resultContext.Column) infos then fallbackExpression ctx else { resultContext with WriterModel = { resultContext.WriterModel with Mode = ctx.WriterModel.Mode } } @@ -639,7 +639,7 @@ let internal futureNlnCheckMem (f, ctx) = if ctx.WriterModel.IsDummy || not ctx.BreakLines then (false, false) else // Create a dummy context to evaluate length of current operation let dummyCtx : Context = ctx.WithDummy(Queue.empty, keepPageWidth = true) |> f - WriterEvents.isMultiline dummyCtx.WriterEvents, dummyCtx.Column > ctx.Config.PageWidth + WriterEvents.isMultiline dummyCtx.WriterEvents, dummyCtx.Column > ctx.Config.MaxLineLength let internal futureNlnCheck f (ctx : Context) = let (isMultiLine, isLong) = futureNlnCheckMem (f, ctx) @@ -1080,7 +1080,7 @@ let internal lastLineOnlyContains characters (ctx: Context) = let lastLine = (writeEventsOnLastLine ctx |> String.concat "").Trim(characters) let length = String.length lastLine - length = 0 || length < ctx.Config.IndentSpaceNum + length = 0 || length < ctx.Config.IndentSize let private (|CommentOrDefineEvent|_|) we = match we with diff --git a/src/Fantomas/EditorConfig.fs b/src/Fantomas/EditorConfig.fs index 975eabb2d8..44059f9ec3 100644 --- a/src/Fantomas/EditorConfig.fs +++ b/src/Fantomas/EditorConfig.fs @@ -1,7 +1,59 @@ module internal Fantomas.EditorConfig -/// Similar to how to processing of the JSON file happens, this function should the options found in the editor config. -/// The first argument in the return tuple are the options. Listed as (key,value) where key is a member name of the FormatConfig record. Value is either a boolean or an int boxed as object. -/// The second argument in the return tuple are warnings. F.ex. invalid settings -let parseOptionsFromEditorConfig _editorConfig : (string * obj) array * string array = - Array.empty, Array.empty +open Fantomas.FormatConfig + +let supportedProperties = ["max_line_length";"indent_size"] + +let private toEditorConfigName value = + value + |> Seq.map (fun c -> if System.Char.IsUpper(c) then sprintf "_%s" (c.ToString().ToLower()) else c.ToString()) + |> String.concat "" + |> fun s -> s.TrimStart([|'_'|]) + |> fun name -> + if List.contains name supportedProperties then + name + else + sprintf "fsharp_%s" name + +let private fantomasFields = + Reflection.getRecordFields FormatConfig.Default + |> Array.map (fun (propertyName, defaultValue) -> + let editorConfigName = toEditorConfigName propertyName + (editorConfigName, defaultValue)) + +let private (|Number|_|) d = + match System.Int32.TryParse(d) with + | true, d -> Some (box d) + | _ -> None +let private (|Boolean|_|) b = + if b = "true" then Some (box true) + elif b = "false" then Some (box false) + else None + +let parseOptionsFromEditorConfig (editorConfig: Fantomas.EditorConfig.Core.FileConfiguration) = + fantomasFields + |> Array.map (fun (ecn, dv) -> + if editorConfig.Properties.ContainsKey(ecn) then + let ecv = editorConfig.Properties.[ecn] + match ecv with + | Number n -> box n + | Boolean b -> box b + | _ -> dv + else + dv) + |> fun newValues -> + let formatConfigType = FormatConfig.Default.GetType() + Microsoft.FSharp.Reflection.FSharpValue.MakeRecord(formatConfigType, newValues) :?> FormatConfig + +let configToEditorConfig (config: FormatConfig): string = + Reflection.getRecordFields config + |> Array.choose (fun (k,v) -> + match v with + | :? System.Boolean as b -> + sprintf "%s=%s" (toEditorConfigName k) (if b then "true " else "false") + |> Some + | :? System.Int32 as i -> + sprintf " %s=%d" (toEditorConfigName k) i + |> Some + | _ -> None) + |> String.concat "\n" \ No newline at end of file diff --git a/src/Fantomas/FakeHelpers.fs b/src/Fantomas/FakeHelpers.fs index db01fd8365..e489293ba5 100644 --- a/src/Fantomas/FakeHelpers.fs +++ b/src/Fantomas/FakeHelpers.fs @@ -64,21 +64,22 @@ let formatContentAsync config (file: string) (originalContent: string) = | ex -> return Error(file, ex) } -let formatFileAsync config (file : string) = +let formatFileAsync (file : string) = + let config = CodeFormatter.ReadConfiguration(file) let originalContent = File.ReadAllText file async { let! formatted = originalContent |> formatContentAsync config file return formatted } -let formatFilesAsync config files = +let formatFilesAsync files = files - |> Seq.map (formatFileAsync config) + |> Seq.map formatFileAsync |> Async.Parallel -let formatCode config files = +let formatCode files = async { - let! results = files |> formatFilesAsync config + let! results = formatFilesAsync files // Check for formatting errors: let errors = @@ -119,10 +120,10 @@ type CheckResult = /// Returns: /// /// A record with the file names that were formatted and the files that encounter problems while formatting. -let checkCode (config: FormatConfig) (filenames: seq) = +let checkCode (filenames: seq) = async { let! formatted = filenames - |> Seq.map (formatFileAsync config) + |> Seq.map formatFileAsync |> Async.Parallel let getChangedFile = diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj index 81172ba8fd..f08c9a6eb3 100644 --- a/src/Fantomas/Fantomas.fsproj +++ b/src/Fantomas/Fantomas.fsproj @@ -3,7 +3,8 @@ netstandard2.0 - 4.0.0-alpha-011 + true + 4.0.0-alpha-012 Source code formatter for F# @@ -17,8 +18,6 @@ - - @@ -35,7 +34,16 @@ - + + + $(MSBuildThisFileDirectory)bin\$(Configuration)\$(TargetFramework) + + + + + + + \ No newline at end of file diff --git a/src/Fantomas/FormatConfig.fs b/src/Fantomas/FormatConfig.fs index 80c709dcdc..e3c9eb4f45 100644 --- a/src/Fantomas/FormatConfig.fs +++ b/src/Fantomas/FormatConfig.fs @@ -9,13 +9,12 @@ type FormatException(msg : string) = type Num = int -// NOTE: try to keep this list below in sync with the schema.json -// and the docs (e.g. Documentation.md) +// NOTE: try to keep this list below in sync with the docs (e.g. Documentation.md) type FormatConfig = { /// Number of spaces for each indentation - IndentSpaceNum : Num + IndentSize : Num /// The column where we break to new lines - PageWidth : Num + MaxLineLength : Num SemicolonAtEndOfLine : bool SpaceBeforeParameter: bool SpaceBeforeLowercaseInvocation: bool @@ -39,12 +38,12 @@ type FormatConfig = KeepIfThenInSameLine : bool MaxElmishWidth: Num SingleArgumentWebMode: bool - /// Prettyprinting based on ASTs only + /// Pretty printing based on ASTs only StrictMode : bool } static member Default = - { IndentSpaceNum = 4 - PageWidth = 120 + { IndentSize = 4 + MaxLineLength = 120 SemicolonAtEndOfLine = false SpaceBeforeParameter = true SpaceBeforeLowercaseInvocation = true @@ -69,18 +68,3 @@ type FormatConfig = SingleArgumentWebMode = false NewlineBetweenTypeDefinitionAndMembers = false StrictMode = false } - - static member ApplyOptions(currentConfig, options) = - let currentValues = Reflection.getRecordFields currentConfig - let newValues = - Array.fold (fun acc (k,v) -> - Array.map (fun (fn, ev) -> if fn = k then (fn, v) else (fn,ev)) acc - ) currentValues options - |> Array.map snd - let formatConfigType = FormatConfig.Default.GetType() - Microsoft.FSharp.Reflection.FSharpValue.MakeRecord (formatConfigType, newValues) :?> FormatConfig - -type FormatConfigFileParseResult = - | Success of FormatConfig - | PartialSuccess of config: FormatConfig * warnings: string list - | Failure of exn diff --git a/src/Fantomas/JsonConfig.fs b/src/Fantomas/JsonConfig.fs deleted file mode 100644 index c66a323fe5..0000000000 --- a/src/Fantomas/JsonConfig.fs +++ /dev/null @@ -1,20 +0,0 @@ -module internal Fantomas.JsonConfig - -open System -open System.Text.RegularExpressions - -let parseOptionsFromJson json = - let results = - Regex.Replace(json, "\s|{|}", String.Empty).Split([|','|]) - |> Array.map (fun line -> line, line.Split([|':'|])) - |> Array.choose (fun (line, pieces) -> - if Array.length pieces = 2 && pieces.[0] <> "$schema" - then Some(line, pieces.[0], pieces.[1]) - else None) - |> Array.map(fun (line, key,value) -> - ConfigFile.processSetting line key value - ) - - let options = Array.choose (function | Ok r -> Some r | _ -> None) results - let warnings = Array.choose (function | Error r -> Some r | _ -> None) results - options, warnings diff --git a/src/Fantomas/Utils.fs b/src/Fantomas/Utils.fs index 544e48ee99..f3ce62fcbc 100644 --- a/src/Fantomas/Utils.fs +++ b/src/Fantomas/Utils.fs @@ -129,19 +129,3 @@ module Reflection = let names = FSharpType.GetRecordFields (x.GetType()) |> Seq.map (fun x -> x.Name) let values = FSharpValue.GetRecordFields x Seq.zip names values |> Seq.toArray - -module Config = - let configToJson config = - Reflection.getRecordFields config - |> Array.choose (fun (k,v) -> - match v with - | :? System.Boolean as b -> - sprintf "\"%s\":%s" k (if b then "true " else "false") - |> Some - | :? System.Int32 as i -> - sprintf " \"%s\":%d" k i - |> Some - | _ -> None - ) - |> String.concat ",\n " - |> sprintf "{ %s }" \ No newline at end of file diff --git a/src/Fantomas/paket.references b/src/Fantomas/paket.references index 925ffd2d59..40384a926a 100644 --- a/src/Fantomas/paket.references +++ b/src/Fantomas/paket.references @@ -1,2 +1,4 @@ FSharp.Compiler.Service -FSharp.Core \ No newline at end of file +FSharp.Core +Fantomas.EditorConfig.Core +ILRepack.MSBuild.Task \ No newline at end of file diff --git a/src/Fantomas/schema.json b/src/Fantomas/schema.json deleted file mode 100644 index 7dcfb7ae72..0000000000 --- a/src/Fantomas/schema.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "properties": { - "IndentSpaceNum": { - "type": "integer" - }, - "PageWidth": { - "type": "integer" - }, - "SemicolonAtEndOfLine": { - "type": "boolean" - }, - "SpaceBeforeParameter": { - "type": "boolean" - }, - "SpaceBeforeLowercaseInvocation": { - "type": "boolean" - }, - "SpaceBeforeUppercaseInvocation": { - "type": "boolean" - }, - "SpaceBeforeClassConstructor": { - "type": "boolean" - }, - "SpaceBeforeMember": { - "type": "boolean" - }, - "SpaceBeforeColon": { - "type": "boolean" - }, - "SpaceAfterComma": { - "type": "boolean" - }, - "SpaceBeforeSemicolon": { - "type": "boolean" - }, - "SpaceAfterSemicolon": { - "type": "boolean" - }, - "IndentOnTryWith": { - "type": "boolean" - }, - "SpaceAroundDelimiter": { - "type": "boolean" - }, - "MaxIfThenElseShortWidth": { - "type": "integer" - }, - "KeepIfThenInSameLine": { - "type": "boolean" - }, - "MaxInfixOperatorExpression": { - "type": "integer" - }, - "MaxRecordWidth": { - "type": "integer" - }, - "MaxArrayOrListWidth": { - "type": "integer" - }, - "MaxValueBindingWidth": { - "type": "integer" - }, - "MaxFunctionBindingWidth": { - "type": "integer" - }, - "MultilineBlockBracketsOnSameColumn": { - "type": "boolean" - }, - "NewlineBetweenTypeDefinitionAndMembers": { - "type": "boolean" - }, - "MaxElmishWidth": { - "type": "integer" - }, - "SingleArgumentWebMode": { - "type": "boolean" - }, - "StrictMode": { - "type": "boolean" - } - }, - "required": [] -} \ No newline at end of file