├── .github └── dependabot.yml ├── .gitignore ├── Readme.md ├── Release Notes.md ├── Usage.md ├── build.ps1 └── src ├── .gitignore ├── FantomasVs.Shared ├── ContentTypeNames.cs ├── CustomLineChunker.cs ├── FantomasHandler.cs ├── FantomasOptionsPage.cs ├── FantomasVs.Shared.projitems ├── FantomasVs.Shared.shproj ├── FantomasVsPackage.cs ├── InstallChoice.xaml ├── InstallChoice.xaml.cs ├── InstallResultDialog.xaml ├── InstallResultDialog.xaml.cs ├── OuptutLogging.cs ├── PredefinedCommandHandlerNames.cs └── Theme.cs ├── FantomasVs.VS2019 ├── FantomasVs.VS2019.csproj ├── Properties │ └── AssemblyInfo.cs ├── source.extension.vsixmanifest └── template.vsixmanifest ├── FantomasVs.VS2022 ├── FantomasVs.VS2022.csproj ├── Properties │ └── AssemblyInfo.cs ├── source.extension.vsixmanifest └── template.vsixmanifest ├── FantomasVs.sln ├── ReleaseNotes.html └── Resources ├── License.txt ├── ReleaseNotes.html └── logo.png /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/src/FantomasVs.VS2019" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | allow: 10 | - dependency-name: "Fantomas.Client" 11 | - package-ecosystem: nuget 12 | directory: "/src/FantomasVs.VS2022" 13 | schedule: 14 | interval: daily 15 | time: "10:00" 16 | open-pull-requests-limit: 10 17 | allow: 18 | - dependency-name: "Fantomas.Client" 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | *.vsix 34 | 35 | #Rider 36 | .idea/ -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Formatting For F# 2 | 3 | This is a front-end for the wonderful [**Fantomas**](https://github.com/fsprojects/fantomas/) project. 4 | 5 | ## Features 6 | 7 | - Format Document 8 | - Format Selection 9 | - Format On Save 10 | - Patching in formatting changes 11 | - Fast, in-process formatting 12 | - Fully asynchronous, does not increase project load times 13 | - Loaded when required 14 | - Respects key-bindings 15 | 16 | ## Options 17 | 18 | Formatting options can be found in `F# Tools > Formatting` 19 | 20 | ![image](https://user-images.githubusercontent.com/2375486/86393459-bc75d800-bcba-11ea-8619-1acb625eacef.png) 21 | 22 | ## In action 23 | 24 | ![](https://user-images.githubusercontent.com/2375486/86392536-3c02a780-bcb9-11ea-8412-7bbf7c164408.gif) 25 | 26 | ## See an issue? 27 | 28 | If you see an issue with the Visual Studio integration or with configuration, please [file it here](https://github.com/deviousasti/fsharp-formatting-for-vs/issues). 29 | 30 | ## License 31 | 32 | This project is licensed under the MIT license, a copy of which can be found [here](src/License.txt). -------------------------------------------------------------------------------- /Release Notes.md: -------------------------------------------------------------------------------- 1 | Release Notes 2 | ============ 3 | 4 | 1.3.0 5 | ----- 6 | * Add initial support for Fantomas cursor 7 | * Upgrade `Fantomas.Client` to `0.7.0` (#51) 8 | 9 | 1.2.0 10 | ----- 11 | * Fix dotnet tool install name and fantomas docs link (#41) thanks to @AkosLukacs 12 | * Fix broken documentation links (#42) 13 | * Upgrade `Fantomas.Client` to `0.7.0` (#42) 14 | * Upgrade `editorconfig` to `0.13` (#42) 15 | 16 | 1.1.0 17 | ----- 18 | * Improved logging and better diagnostics 19 | * Update `Fantomas.Client` to `0.5.4` 20 | 21 | 1.0 22 | ---- 23 | 24 | * Use `Fantomas.Client` which supports installing and using Fantomas as a dotnet tools instead of being bundled with the extension 25 | 26 | 0.9.4 27 | ---- 28 | 29 | * Update Fantomas to 4.5.8 30 | 31 | 0.9.3 32 | ---- 33 | 34 | * Update Fantomas to 4.5.5 35 | 36 | 0.9.2 37 | ---- 38 | 39 | * Update Fantomas to 4.5.4 40 | 41 | 0.9.1 42 | ---- 43 | 44 | * Update stable Fantomas to 4.5.1 45 | * Update latest Fantomas to 4.5.1 46 | * Add 'Always place bar in front of discriminated union' option 47 | 48 | 0.9 49 | ---- 50 | 51 | * Update to Fantomas to 4.5 alpha 17 52 | * Add guard to diff algorithm 53 | 54 | 0.8.4 55 | ---- 56 | 57 | * Implement diff shrinking for minimal edit surface 58 | 59 | 0.8.3 60 | ---- 61 | 62 | * Unix line-endings supported with diff 63 | * Implement line-ending agnostic chunker 64 | 65 | 0.8.2 66 | ---- 67 | 68 | * Update stable Fantomas to 4.4.0 69 | * Update latest to 4.5.0 alpha 70 | 71 | 0.8.1 72 | ---- 73 | 74 | * Formatting defaults to stable version 75 | * Update Fantomas to 4.4.0-beta-008 76 | 77 | 0.8 78 | ---- 79 | 80 | * Change project build structure 81 | * Support both latest (bleeding edge) and stable versions configurable by an option 82 | * Update Fantomas to 4.4.0-beta-003 83 | 84 | 0.7.3 85 | ---- 86 | 87 | * Add options to allow to not commit changes caused by format-on-save 88 | 89 | 0.7.2 90 | ---- 91 | 92 | * Format on Save forces save if formatting results in a change 93 | * Update Fantomas to 4.4.0 alpha 94 | * Update to FCS 38.0.2 95 | 96 | 0.7.1 97 | ---- 98 | 99 | * Fantomas Bugfix release 100 | * Fantomas 4.3 101 | 102 | 0.7 103 | ---- 104 | 105 | * Built against Fantomas 4.3 alpha 106 | * Add support for line-ending options (and more) 107 | 108 | 0.6 109 | ---- 110 | 111 | * Update to FCS 38 112 | * Built against Fantomas 4.2 113 | 114 | 0.5 115 | ---- 116 | 117 | * Support MultilineFormatter selection and additional options 118 | * Built against Fantomas late September release 119 | 120 | 0.4.6 121 | ---- 122 | 123 | * Built against Fantomas 4.1.1 stable 124 | 125 | 0.4.5 126 | ---- 127 | 128 | * Built against Fantomas 4.1 September release 129 | 130 | 0.4.4 131 | ---- 132 | 133 | * Fantomas 4.0.0 stable August release 134 | * Format selection in Fantomas instead of isolated selection (still sensitive to whitespace) 135 | 136 | 0.4.3 137 | ---- 138 | 139 | * Moved to FCS 37.0 140 | * Built against 4.0.0 beta-004 141 | 142 | 0.4.2 143 | ---- 144 | 145 | * Built against 4.0.0 beta-002 146 | * Directly built for net48, no ILRepack 147 | 148 | 0.4.1 149 | ---- 150 | 151 | * Built against 4.0.0 beta-001 152 | * Upgrade vs build tools 153 | 154 | 0.4 155 | ---- 156 | 157 | * Add MIT license 158 | * Built against 4.0.0 alpha-013 159 | 160 | 0.3 161 | ---- 162 | 163 | * Add support for .editorconfig 164 | * Falls back to Visual Stuio configuration if no .editorconfig settings are found 165 | * Built against 4.0.0 alpha (17bfa28ad) 166 | 167 | 0.2 168 | ---- 169 | 170 | * Built against 4.0.0 alpha (28ed449c) 171 | * Update format settings in VS config 172 | 173 | 0.1 174 | ---- 175 | 176 | * Initial Release 177 | * Built against 3.0.0 178 | * Document Format 179 | * Selection Format 180 | * Format on Save 181 | * Diff format 182 | 183 | -------------------------------------------------------------------------------- /Usage.md: -------------------------------------------------------------------------------- 1 | # Formatting For F# 2 | 3 | This extension serves as the default code formatter for F# source files (`.fs`, `.fsi`, `.fsx`). 4 | 5 | Formatting is generated by the wonderful [**Fantomas**](https://github.com/fsprojects/fantomas/) project. 6 | 7 | ## Features 8 | 9 | - Format Document 10 | - Format Selection 11 | - Format On Save 12 | - Supports editorconfig 13 | - Patching in formatting changes 14 | - Fast, in-process formatting 15 | - Fully asynchronous, does not increase project load times 16 | - Loaded when required 17 | - Respects key-bindings 18 | 19 | ## Options 20 | 21 | This extension supports [editor config](https://editorconfig.org), for documentation of the options see [Fantomas documentation](https://github.com/fsprojects/fantomas/blob/master/docs/Documentation.md#configuration). 22 | 23 | If no settings can be found for a file, the user profile's formatting options are used. 24 | These can be configured from `F# Tools > Formatting` 25 | 26 | ![image](https://user-images.githubusercontent.com/2375486/86393459-bc75d800-bcba-11ea-8619-1acb625eacef.png) 27 | 28 | ## Usage 29 | 30 | Any custom key-bindings for Format Document/Selection are respected. The default key-bindings are `ctrl-k + ctrl-d` for document formatting and `ctrl-k + ctrl-f` for formatting a selection. 31 | 32 | ![](https://user-images.githubusercontent.com/2375486/86392536-3c02a780-bcb9-11ea-8412-7bbf7c164408.gif) 33 | 34 | ## See an issue? 35 | 36 | If you see an issue with the Visual Studio integration or with configuration, please [file it here](https://github.com/deviousasti/fsharp-formatting-for-vs/issues). 37 | 38 | ## License 39 | 40 | F# Formatting is available under the [MIT license](https://mit-license.org). -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | del .\src\bin\* -Recurse 2 | # npm i -g markdown-to-html-cli 3 | markdown-to-html-cli --source '.\Release Notes.md' --output src/Resources/ReleaseNotes.html 4 | msbuild .\src\FantomasVs.sln -p:Configuration=Release 5 | copy .\src\FantomasVs.VS2019\bin\Release\FantomasVs.vsix .\FantomasVs.VS2019.vsix 6 | copy .\src\FantomasVs.VS2022\bin\Release\FantomasVs.vsix .\FantomasVs.VS2022.vsix -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/ContentTypeNames.cs: -------------------------------------------------------------------------------- 1 | namespace FantomasVs 2 | { 3 | internal static class ContentTypeNames 4 | { 5 | public const string FSharpContentType = "F#"; 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/CustomLineChunker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DiffPlex; 3 | using System.Collections.Generic; 4 | 5 | namespace FantomasVs 6 | { 7 | public class AgnosticChunker : IChunker 8 | { 9 | /// 10 | /// Gets the default singleton instance of the chunker. 11 | /// 12 | public static AgnosticChunker Instance { get; } = new AgnosticChunker(); 13 | 14 | public string[] Chunk(string text) 15 | { 16 | if (string.IsNullOrEmpty(text)) 17 | return Array.Empty(); 18 | 19 | var output = new List(128); 20 | 21 | int lastPosition = 0, currentPosition = 0; 22 | 23 | while (currentPosition < text.Length) 24 | { 25 | char ch = text[currentPosition]; 26 | switch (ch) 27 | { 28 | case '\n': 29 | case '\r': 30 | { 31 | 32 | if (ch == '\r' && currentPosition < text.Length && text[currentPosition + 1] == '\n') 33 | currentPosition += 2; 34 | else 35 | currentPosition += 1; 36 | 37 | var str = text.Substring(lastPosition, currentPosition - lastPosition); 38 | output.Add(str); 39 | 40 | lastPosition = currentPosition; 41 | break; 42 | } 43 | 44 | default: 45 | { 46 | currentPosition += 1; 47 | break; 48 | } 49 | } 50 | } 51 | 52 | if (lastPosition != text.Length) 53 | { 54 | var str = text.Substring(lastPosition, text.Length - lastPosition); 55 | output.Add(str); 56 | } 57 | 58 | return output.ToArray(); 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/FantomasHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DiffPlex; 3 | using System.ComponentModel.Composition; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | using Microsoft.VisualStudio.Commanding; 10 | using Microsoft.VisualStudio.Text; 11 | using Microsoft.VisualStudio.Text.Editor.Commanding; 12 | using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; 13 | using Microsoft.VisualStudio.Utilities; 14 | using Microsoft.VisualStudio; 15 | using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper; 16 | using ThreadedWaitDialogHelper = Microsoft.VisualStudio.Shell.ThreadedWaitDialogHelper; 17 | 18 | using Fantomas.Client; 19 | using FantomasResponseCode = Fantomas.Client.LSPFantomasServiceTypes.FantomasResponseCode; 20 | using Microsoft.VisualStudio.Threading; 21 | 22 | namespace FantomasVs 23 | { 24 | [Export] 25 | [Export(typeof(ICommandHandler))] 26 | [ContentType(ContentTypeNames.FSharpContentType)] 27 | [Name(PredefinedCommandHandlerNames.FormatDocument)] 28 | [Order(After = PredefinedCommandHandlerNames.Rename)] 29 | public partial class FantomasHandler : 30 | ICommandHandler, 31 | ICommandHandler, 32 | ICommandHandler 33 | { 34 | public string DisplayName => "Automatic Formatting"; 35 | 36 | #region Patching 37 | 38 | protected bool ReplaceAll(Span span, ITextBuffer buffer, string oldText, string newText) 39 | { 40 | if (oldText == newText) 41 | return false; 42 | 43 | buffer.Replace(span, newText); 44 | return true; 45 | } 46 | 47 | private (int, int) ShrinkDiff(string currentText, string replaceWith) 48 | { 49 | int startOffset = 0, endOffset = 0; 50 | var currentLength = currentText.Length; 51 | var replaceLength = replaceWith.Length; 52 | 53 | var length = Math.Min(currentLength, replaceLength); 54 | 55 | for (int i = 0; i < length; i++) 56 | { 57 | if (currentText[i] == replaceWith[i]) 58 | startOffset++; 59 | else 60 | break; 61 | } 62 | 63 | for (int i = 1; i < length; i++) 64 | { 65 | if ((startOffset + endOffset) >= length) 66 | break; 67 | 68 | if (currentText[currentLength - i] == replaceWith[replaceLength - i]) 69 | endOffset++; 70 | else 71 | break; 72 | } 73 | 74 | return (startOffset, endOffset); 75 | } 76 | 77 | protected bool DiffPatch(Span span, ITextBuffer buffer, string oldText, string newText) 78 | { 79 | var snapshot = buffer.CurrentSnapshot; 80 | 81 | using var edit = buffer.CreateEdit(); 82 | var diff = Differ.Instance.CreateDiffs(oldText, newText, false, false, AgnosticChunker.Instance); 83 | var lineOffset = snapshot.GetLineNumberFromPosition(span.Start); 84 | 85 | int StartOf(int line) => 86 | snapshot 87 | .GetLineFromLineNumber(line) 88 | .Start 89 | .Position; 90 | 91 | foreach (var current in diff.DiffBlocks) 92 | { 93 | var start = lineOffset + current.DeleteStartA; 94 | 95 | if (current.DeleteCountA == current.InsertCountB && 96 | (current.DeleteStartA + current.DeleteCountA) < snapshot.LineCount) 97 | { 98 | var count = current.InsertCountB; 99 | var lstart = StartOf(start); 100 | var lend = StartOf(start + count); 101 | var currentText = snapshot.GetText(lstart, lend - lstart); 102 | var replaceWith = count == 1 ? 103 | diff.PiecesNew[current.InsertStartB] : 104 | string.Join("", diff.PiecesNew, current.InsertStartB, current.InsertCountB); 105 | var (startOffset, endOffset) = ShrinkDiff(currentText, replaceWith); 106 | var totalOffset = startOffset + endOffset; 107 | 108 | var minReplaceWith = replaceWith.Substring(startOffset, replaceWith.Length - totalOffset); 109 | 110 | edit.Replace(lstart + startOffset, Math.Max(0, lend - lstart - totalOffset), minReplaceWith); 111 | } 112 | else 113 | { 114 | 115 | for (int i = 0; i < current.DeleteCountA; i++) 116 | { 117 | var ln = snapshot.GetLineFromLineNumber(start + i); 118 | edit.Delete(ln.Start, ln.LengthIncludingLineBreak); 119 | } 120 | 121 | for (int i = 0; i < current.InsertCountB; i++) 122 | { 123 | var ln = snapshot.GetLineFromLineNumber(start); 124 | edit.Insert(ln.Start, diff.PiecesNew[current.InsertStartB + i]); 125 | } 126 | } 127 | } 128 | 129 | edit.Apply(); 130 | 131 | return diff.DiffBlocks.Any(); 132 | } 133 | 134 | #endregion 135 | 136 | #region Formatting 137 | 138 | public enum FormatKind 139 | { 140 | Document, 141 | Selection, 142 | IsolatedSelection 143 | } 144 | 145 | public bool CommandHandled => true; 146 | 147 | public async Task FormatAsync(SnapshotSpan vspan, EditorCommandArgs args, CommandExecutionContext context, FormatKind kind) 148 | { 149 | var token = context.OperationContext.UserCancellationToken; 150 | var instance = await FantomasVsPackage.Instance.WithCancellation(token); 151 | 152 | await SetStatusAsync("Formatting...", instance, token); 153 | await Task.Yield(); 154 | 155 | var buffer = args.TextView.TextBuffer; 156 | var caret = args.TextView.Caret.Position; 157 | 158 | var service = instance.FantomasService; 159 | var fantopts = instance.Options; 160 | var document = buffer.Properties.GetProperty(typeof(ITextDocument)); 161 | var path = document.FilePath; 162 | var workingDir = System.IO.Path.GetDirectoryName(path); 163 | var hasDiff = false; 164 | var hasError = false; 165 | 166 | try 167 | { 168 | var originText = kind switch 169 | { 170 | FormatKind.Document => buffer.CurrentSnapshot.GetText(), 171 | FormatKind.Selection => buffer.CurrentSnapshot.GetText(), 172 | FormatKind.IsolatedSelection => vspan.GetText(), 173 | _ => throw new NotSupportedException($"Operation {kind} is not supported") 174 | }; 175 | var response = await (kind switch 176 | { 177 | FormatKind.Document or FormatKind.IsolatedSelection => 178 | service.FormatDocumentAsync(new Contracts.FormatDocumentRequest(originText, path, null, MakeCursorPosition(caret.BufferPosition)), token), 179 | FormatKind.Selection => 180 | service.FormatSelectionAsync(new Contracts.FormatSelectionRequest(originText, path, null, MakeRange(vspan, path)), token), 181 | _ => throw new NotSupportedException($"Operation {kind} is not supported") 182 | }); 183 | 184 | switch ((FantomasResponseCode)response.Code) 185 | { 186 | case FantomasResponseCode.Formatted: 187 | { 188 | var newText = response.Content.Value; 189 | var oldText = vspan.GetText(); 190 | 191 | if (fantopts.ApplyDiff) 192 | { 193 | hasDiff = DiffPatch(vspan, buffer, oldText, newText); 194 | } 195 | else 196 | { 197 | hasDiff = ReplaceAll(vspan, buffer, oldText, newText); 198 | } 199 | break; 200 | } 201 | case FantomasResponseCode.UnChanged: 202 | case FantomasResponseCode.Ignored: 203 | break; 204 | case FantomasResponseCode.ToolNotFound: 205 | { 206 | var view = new InstallChoiceWindow(); 207 | var result = await InstallAsync(view.GetDialogAction(), workingDir, token); 208 | switch (result) 209 | { 210 | case InstallResult.Succeded: 211 | { 212 | InstallResultDialog.ShowDialog("Fantomas Tool was succesfully installed!"); 213 | using (var session = ThreadedWaitDialogHelper.StartWaitDialog(instance.DialogFactory, "Starting instance...")) 214 | { 215 | await FormatAsync(vspan, args, context, kind); 216 | } 217 | break; 218 | } 219 | case InstallResult.Failed: 220 | { 221 | hasError = true; 222 | InstallResultDialog.ShowDialog("Fantomas Tool could not be installed. You may not have a tool manifest set up. Please check the log for details."); 223 | await FocusLogAsync(token); 224 | break; 225 | } 226 | } 227 | 228 | break; 229 | } 230 | 231 | case FantomasResponseCode.Error: 232 | case FantomasResponseCode.FileNotFound: 233 | case FantomasResponseCode.FilePathIsNotAbsolute: 234 | { 235 | hasError = true; 236 | var error = response.Content.Value; 237 | await SetStatusAsync($"Could not format: {error.Replace(path, "")}", instance, token); 238 | await WriteLogAsync(error, token); 239 | await FocusLogAsync(token); 240 | break; 241 | } 242 | case FantomasResponseCode.DaemonCreationFailed: 243 | { 244 | await WriteLogAsync($"Creating the Fantomas Daemon failed:\n{response.Content?.Value}", token); 245 | await FocusLogAsync(token); 246 | hasError = true; 247 | break; 248 | } 249 | default: 250 | throw new NotSupportedException($"The {nameof(FantomasResponseCode)} value '{response.Code}' is unexpected.\n Error: {response.Content?.Value}"); 251 | } 252 | 253 | if(hasError) 254 | { 255 | await WriteLogAsync("Attempting to find Fantomas Tool...", token); 256 | var folder = LSPFantomasServiceTypes.Folder.NewFolder(workingDir); 257 | var toolLocation = FantomasToolLocator.findFantomasTool(folder); 258 | var result = toolLocation.IsError ? $"Failed to find tool: {toolLocation.ErrorValue}" : $"Found at: {toolLocation.ResultValue}"; 259 | await WriteLogAsync(result, token); 260 | } 261 | } 262 | catch (NotSupportedException ex) 263 | { 264 | await WriteLogAsync($"The operation is not supported:\n {ex.Message}", token); 265 | } 266 | catch (Exception ex) 267 | { 268 | hasError = true; 269 | await WriteLogAsync($"The formatting operation failed:\n {ex}", token); 270 | await SetStatusAsync($"Could not format: {ex.Message.Replace(path, "")}", instance, token); 271 | } 272 | 273 | args.TextView.Caret.MoveTo( 274 | caret 275 | .BufferPosition 276 | .TranslateTo(buffer.CurrentSnapshot, PointTrackingMode.Positive) 277 | ); 278 | 279 | if (kind == FormatKind.Selection || kind == FormatKind.IsolatedSelection) 280 | args.TextView.Selection.Select( 281 | vspan.TranslateTo(args.TextView.TextSnapshot, SpanTrackingMode.EdgeInclusive), 282 | false); 283 | 284 | if (hasError) await Task.Delay(2000); 285 | await SetStatusAsync("Ready.", instance, token); 286 | 287 | return hasDiff; 288 | } 289 | 290 | protected async Task<(bool, string)> RunProcessAsync(string name, string args, string workingDir, CancellationToken token) 291 | { 292 | var startInfo = new ProcessStartInfo 293 | { 294 | FileName = name, 295 | Arguments = args, 296 | UseShellExecute = false, 297 | RedirectStandardOutput = true, 298 | RedirectStandardError = true, 299 | CreateNoWindow = true, 300 | WorkingDirectory = workingDir 301 | }; 302 | 303 | try 304 | { 305 | using var process = Process.Start(startInfo); 306 | var exitCode = await process.WaitForExitAsync(token); 307 | 308 | token.ThrowIfCancellationRequested(); 309 | 310 | var output = exitCode switch 311 | { 312 | 0 => await process.StandardOutput.ReadToEndAsync().WithCancellation(token), 313 | _ => await process.StandardError.ReadToEndAsync().WithCancellation(token) 314 | }; 315 | 316 | return (exitCode == 0, output); 317 | } 318 | catch (Exception ex) 319 | { 320 | return (false, $"Failed to run dotnet tool {ex}"); 321 | } 322 | } 323 | 324 | public async Task InstallAsync(InstallAction installAction, string workingDir, CancellationToken token) 325 | { 326 | async Task LaunchUrl(string uri) 327 | { 328 | try 329 | { 330 | Process.Start(new ProcessStartInfo(uri) { UseShellExecute = true }); 331 | } 332 | catch (Exception ex) 333 | { 334 | await WriteLogAsync($"Failed to launch url: {uri}\n{ex}", token); 335 | } 336 | 337 | return InstallResult.Skipped; 338 | } 339 | 340 | async Task LaunchDotnet(string caption, string args) 341 | { 342 | await WriteLogAsync(caption, token); 343 | await WriteLogAsync("Running dotnet installation...", token); 344 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(token); 345 | var instance = await FantomasVsPackage.Instance; 346 | using var session = ThreadedWaitDialogHelper.StartWaitDialog(instance.DialogFactory, caption); 347 | var (success, output) = await RunProcessAsync("dotnet", args, workingDir, session.UserCancellationToken); 348 | await WriteLogAsync(output, token); 349 | return success ? InstallResult.Succeded : InstallResult.Failed; 350 | } 351 | 352 | return installAction switch 353 | { 354 | InstallAction.Global => await LaunchDotnet("Installing tool globally", "tool install --verbosity normal --global fantomas"), 355 | InstallAction.Local => await LaunchDotnet("Installing tool locally", "tool install --verbosity normal fantomas"), 356 | InstallAction.ShowDocs => await LaunchUrl("https://fsprojects.github.io/fantomas/docs/index.html"), 357 | _ => InstallResult.Skipped, // do nothing 358 | }; 359 | } 360 | 361 | public static Contracts.FormatCursorPosition MakeCursorPosition(SnapshotPoint point) 362 | { 363 | var line = point.GetContainingLine(); 364 | var startCol = Math.Max(0, point.Position - line.Start.Position - 1); 365 | return new Contracts.FormatCursorPosition(line.LineNumber + 1, startCol); 366 | } 367 | 368 | public static Contracts.FormatSelectionRange MakeRange(SnapshotSpan vspan, string path) 369 | { 370 | // Beware that the range argument is inclusive. 371 | // If the range has a trailing newline, it will appear in the formatted result. 372 | 373 | var start = vspan.Start.GetContainingLine(); 374 | var end = vspan.End.GetContainingLine(); 375 | var startLine = start.LineNumber + 1; 376 | var startCol = Math.Max(0, vspan.Start.Position - start.Start.Position - 1); 377 | var endLine = end.LineNumber + 1; 378 | var endCol = Math.Max(0, vspan.End.Position - end.Start.Position - 1); 379 | 380 | var range = new Contracts.FormatSelectionRange( 381 | startLine: startLine, 382 | startColumn: startCol, 383 | endLine: endLine, 384 | endColumn: endCol); 385 | return range; 386 | } 387 | 388 | public Task FormatAsync(EditorCommandArgs args, CommandExecutionContext context) 389 | { 390 | var snapshot = args.TextView.TextSnapshot; 391 | var vspan = new SnapshotSpan(snapshot, new Span(0, snapshot.Length)); 392 | return FormatAsync(vspan, args, context, FormatKind.Document); 393 | } 394 | 395 | protected async Task SetStatusAsync(string text, FantomasVsPackage instance, CancellationToken token) 396 | { 397 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(token); 398 | var statusBar = instance.Statusbar; 399 | // Make sure the status bar is not frozen 400 | 401 | if (statusBar.IsFrozen(out var frozen) == VSConstants.S_OK && frozen != 0) 402 | statusBar.FreezeOutput(0); 403 | 404 | // Set the status bar text and make its display static. 405 | statusBar.SetText(text); 406 | } 407 | 408 | #endregion 409 | 410 | #region Output Window 411 | 412 | public OuptutLogging Logging { get; } = new(); 413 | 414 | public Task WriteLogAsync(string text, CancellationToken token) => Logging.LogTextAsync(text, token); 415 | 416 | public Task FocusLogAsync(CancellationToken token) => Logging.BringToFrontAsync(token); 417 | 418 | #endregion 419 | 420 | #region Logging 421 | 422 | protected void LogTask(Task task) 423 | { 424 | var _ = task.ContinueWith(async t => 425 | { 426 | if (t.IsFaulted) 427 | await WriteLogAsync(t.Exception.ToString(), CancellationToken.None); 428 | 429 | }, TaskScheduler.Default); 430 | } 431 | 432 | #endregion 433 | 434 | #region Format Document 435 | 436 | public bool ExecuteCommand(FormatDocumentCommandArgs args, CommandExecutionContext executionContext) 437 | { 438 | LogTask(FormatAsync(args, executionContext)); 439 | return CommandHandled; 440 | } 441 | 442 | public CommandState GetCommandState(FormatDocumentCommandArgs args) 443 | { 444 | return args.TextView.IsClosed ? CommandState.Unavailable : CommandState.Available; 445 | } 446 | 447 | #endregion 448 | 449 | #region Format Selection 450 | 451 | public CommandState GetCommandState(FormatSelectionCommandArgs args) 452 | { 453 | return args.TextView.Selection.IsEmpty ? CommandState.Unavailable : CommandState.Available; 454 | } 455 | 456 | public bool ExecuteCommand(FormatSelectionCommandArgs args, CommandExecutionContext executionContext) 457 | { 458 | var selections = args.TextView.Selection.SelectedSpans; 459 | 460 | // This command shouldn't be called 461 | // if there's no selection, but it's bad practice 462 | // to surface exceptions to VS 463 | if (selections.Count == 0) 464 | return false; 465 | 466 | var vspan = new SnapshotSpan(args.TextView.TextSnapshot, selections.Single().Span); 467 | LogTask(FormatAsync(vspan, args, executionContext, FormatKind.Selection)); 468 | return CommandHandled; 469 | } 470 | 471 | #endregion 472 | 473 | #region Format On Save 474 | 475 | public CommandState GetCommandState(SaveCommandArgs args) 476 | { 477 | return CommandState.Unavailable; 478 | } 479 | 480 | public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext executionContext) 481 | { 482 | LogTask(FormatOnSaveAsync(args, executionContext)); 483 | return false; 484 | } 485 | 486 | protected async Task FormatOnSaveAsync(SaveCommandArgs args, CommandExecutionContext executionContext) 487 | { 488 | var instance = await FantomasVsPackage.Instance; 489 | if (!instance.Options.FormatOnSave) 490 | return; 491 | 492 | var hasDiff = await FormatAsync(args, executionContext); 493 | 494 | if (!hasDiff || !instance.Options.CommitChanges) 495 | return; 496 | 497 | var buffer = args.SubjectBuffer; 498 | var document = buffer.Properties.GetProperty(typeof(ITextDocument)); 499 | 500 | document?.Save(); 501 | } 502 | 503 | #endregion 504 | } 505 | } 506 | 507 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/FantomasOptionsPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Microsoft.VisualStudio.Shell; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace FantomasVs 7 | { 8 | [Guid(GuidString)] 9 | public class FantomasOptionsPage : DialogPage 10 | { 11 | public const string GuidString = "74927147-72e8-4b47-a70d-5568807d6878"; 12 | 13 | #region Performance 14 | 15 | [Category("Performance")] 16 | [DisplayName("Apply As Diff")] 17 | [Description("Applies the formatting as changes, which shows which lines were changed. Turn off if computing the diff is too slow. ")] 18 | public bool ApplyDiff { get; set; } = true; 19 | 20 | [Category("Performance")] 21 | [DisplayName("Enable SpaceBar Heating")] 22 | [Description("xkcd/1172")] 23 | public bool EnableSpaceBarHeating { get; set; } = false; 24 | 25 | #endregion 26 | 27 | #region On Save 28 | 29 | [Category("On Save")] 30 | [DisplayName("Format On Save")] 31 | [Description("This triggers a formatting whenever you hit save")] 32 | public bool FormatOnSave { get; set; } = false; 33 | 34 | [Category("On Save")] 35 | [DisplayName("Commit Changes")] 36 | [Description("Set this to false if you don't want to commit formatting changes to the file unless you hit save once again")] 37 | public bool CommitChanges { get; set; } = true; 38 | 39 | #endregion 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/FantomasVs.Shared.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | b7a936ca-e24e-4ea6-9571-1373c6e44614 7 | 8 | 9 | FantomasVs.Shared 10 | 11 | 12 | 13 | 14 | 15 | 16 | Component 17 | 18 | 19 | 20 | InstallChoice.xaml 21 | 22 | 23 | InstallResultDialog.xaml 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | MSBuild:Compile 35 | Designer 36 | 37 | 38 | MSBuild:Compile 39 | Designer 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/FantomasVs.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | b7a936ca-e24e-4ea6-9571-1373c6e44614 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/FantomasVsPackage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Fantomas.Client; 7 | using Microsoft.VisualStudio.ComponentModelHost; 8 | using Microsoft.VisualStudio.Shell; 9 | using Microsoft.VisualStudio.Shell.Interop; 10 | using Task = System.Threading.Tasks.Task; 11 | 12 | namespace FantomasVs 13 | { 14 | 15 | // DO NOT REMOVE THIS MAGICAL INCANTATION NO MATTER HOW MUCH VS WARNS YOU OF DEPRECATION 16 | // -------------------------------------------------------------------------------------- 17 | [InstalledProductRegistration("F# Formatting", "F# source code formatting using Fantomas.", "1.0", IconResourceID = 400)] 18 | // -------------------------------------------------------------------------------------- 19 | 20 | // Package registration attributes 21 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] 22 | [Guid(FantomasVsPackage.PackageGuidString)] 23 | 24 | // Auto load only if a solution is open, this is important too 25 | [ProvideAutoLoad(UIContextGuids80.SolutionExists, PackageAutoLoadFlags.BackgroundLoad)] 26 | 27 | // Options page 28 | [ProvideOptionPage(typeof(FantomasOptionsPage), "F# Tools", "Formatting", 0, 0, supportsAutomation: true)] 29 | 30 | public sealed partial class FantomasVsPackage : AsyncPackage 31 | { 32 | /// 33 | /// FantomasVsPackage GUID string. 34 | /// 35 | public const string PackageGuidString = "74927147-72e8-4b47-a80d-5568807d6878"; 36 | 37 | private static readonly TaskCompletionSource _instance = new(); 38 | public static Task Instance => _instance.Task; 39 | 40 | public FantomasOptionsPage Options => GetDialogPage(typeof(FantomasOptionsPage)) as FantomasOptionsPage ?? new FantomasOptionsPage(); 41 | 42 | public IVsStatusbar Statusbar { get; private set; } 43 | public IVsOutputWindow OutputPane { get; private set; } 44 | public IVsThreadedWaitDialogFactory DialogFactory { get; private set; } 45 | 46 | private Lazy _fantomasService = new (() => new LSPFantomasService.LSPFantomasService()); 47 | public Contracts.FantomasService FantomasService => _fantomasService.Value; 48 | 49 | #region Package Members 50 | 51 | /// 52 | /// Initialization of the package; this method is called right after the package is sited, so this is the place 53 | /// where you can put all the initialization code that rely on services provided by VisualStudio. 54 | /// 55 | /// A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down. 56 | /// A provider for progress updates. 57 | /// A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method. 58 | protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) 59 | { 60 | Trace.WriteLine("Fantomas Vs Package Loaded"); 61 | 62 | Statusbar = await this.GetServiceAsync(); 63 | OutputPane = await this.GetServiceAsync(); 64 | DialogFactory = await this.GetServiceAsync(); 65 | 66 | // signal that package is ready 67 | _instance.SetResult(this); 68 | 69 | // When initialized asynchronously, the current thread may be a background thread at this point. 70 | // Do any initialization that requires the UI thread after switching to the UI thread. 71 | await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); 72 | 73 | } 74 | 75 | protected override void Dispose(bool disposing) 76 | { 77 | if (disposing) 78 | { 79 | try 80 | { 81 | FantomasService.Dispose(); 82 | Trace.WriteLine("Fantomas Vs Package Disposed"); 83 | } 84 | catch (Exception ex) 85 | { 86 | Trace.WriteLine(ex); 87 | } 88 | } 89 | 90 | base.Dispose(disposing); 91 | } 92 | 93 | #endregion 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/InstallChoice.xaml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 30 | 33 | 40 | 41 | 42 | 43 | An installation of the F# source code formatter, Fantomas could not be found. 44 | 45 | 46 | You can choose to install it: 47 | 48 | 49 | 61 | 73 | 84 | 85 | 86 | You can read the documentation to find out more. 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/InstallChoice.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | 18 | namespace FantomasVs 19 | { 20 | public enum InstallAction 21 | { 22 | None, 23 | Global, 24 | Local, 25 | UpdateGlobal, 26 | UpdateLocal, 27 | ShowDocs 28 | } 29 | 30 | public enum InstallResult 31 | { 32 | Skipped, 33 | Succeded, 34 | Failed 35 | } 36 | 37 | /// 38 | /// Interaction logic for InstallChoiceWindow.xaml 39 | /// 40 | public partial class InstallChoiceWindow : DialogWindow 41 | { 42 | class ChoiceCommand : ICommand 43 | { 44 | public Action Action { get; } 45 | 46 | public ChoiceCommand(Action action) 47 | { 48 | Action = action; 49 | } 50 | 51 | public event EventHandler CanExecuteChanged; 52 | 53 | public bool CanExecute(object parameter) => true; 54 | 55 | public void Execute(object parameter) 56 | { 57 | CanExecuteChanged?.Invoke(this, new EventArgs()); 58 | Debug.Assert(parameter is InstallAction); 59 | Action?.Invoke(parameter); 60 | } 61 | } 62 | 63 | public InstallChoiceWindow() 64 | { 65 | InitializeComponent(); 66 | } 67 | 68 | public InstallAction GetDialogAction() 69 | { 70 | var result = InstallAction.None; 71 | void onClick(object parameter) 72 | { 73 | Debug.Assert(parameter is InstallAction); 74 | this.Close(); 75 | result = (InstallAction)parameter; 76 | } 77 | 78 | this.DataContext = new ChoiceCommand(onClick); 79 | this.ShowDialog(); 80 | 81 | return result; 82 | } 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /src/FantomasVs.Shared/InstallResultDialog.xaml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Fantomas Tool 42 | 43 | To view logs, select 'F# Formatting' in the Output Window. 44 | 45 | 46 | See documentation on how to configure style 47 | 48 | Try out options in online preview 49 | 50 | Visit the project page 51 | 52 | Learn about dotnet local tools 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/InstallResultDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | 18 | namespace FantomasVs 19 | { 20 | /// 21 | /// Interaction logic for ModalDialogWindow.xaml 22 | /// 23 | public partial class InstallResultDialog : DialogWindow 24 | { 25 | public InstallResultDialog() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | public void ShowModal(string text) 31 | { 32 | this.MessageText.Text = text; 33 | MessageContent.Document.Blocks 34 | .OfType() 35 | .SelectMany(c => c.Inlines) 36 | .OfType() 37 | .ToList() 38 | .ForEach(block => { 39 | var uri = block.NavigateUri.AbsoluteUri; 40 | block.RequestNavigate += (s, e) => 41 | { 42 | Process.Start(new ProcessStartInfo(uri) { UseShellExecute = true }); 43 | }; 44 | block.ToolTip = $"Open {uri}"; 45 | }); 46 | this.CloseButton.Click += (s, e) => this.Close(); 47 | this.ShowModal(); 48 | } 49 | 50 | public static void ShowDialog(string text) 51 | { 52 | new InstallResultDialog().ShowModal(text); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/FantomasVs.Shared/OuptutLogging.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio; 3 | using Microsoft.VisualStudio.Shell; 4 | using System.Threading.Tasks; 5 | using OutputPane = Microsoft.VisualStudio.Shell.Interop.IVsOutputWindowPane; 6 | using System.Diagnostics; 7 | using System.Threading; 8 | using Task = System.Threading.Tasks.Task; 9 | 10 | namespace FantomasVs 11 | { 12 | public class OuptutLogging 13 | { 14 | private OutputPane _instance; 15 | 16 | private async Task CreatePaneAsync(Guid paneGuid, string title, bool visible, bool clearWithSolution) 17 | { 18 | var instance = await FantomasVsPackage.Instance; 19 | var output = instance.OutputPane; 20 | 21 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); 22 | 23 | // Create a new pane. 24 | output.CreatePane( 25 | ref paneGuid, 26 | title, 27 | Convert.ToInt32(visible), 28 | Convert.ToInt32(clearWithSolution)); 29 | 30 | // Retrieve the new pane. 31 | if (output.GetPane(ref paneGuid, out var pane) != VSConstants.S_OK) 32 | throw new InvalidOperationException(); 33 | 34 | return pane; 35 | } 36 | 37 | private Task CreatePaneAsync() 38 | { 39 | return CreatePaneAsync(new Guid(FantomasVsPackage.PackageGuidString), "F# Formatting", true, false); 40 | } 41 | 42 | public async Task GetPaneAsync(CancellationToken token) 43 | { 44 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(token); 45 | if (_instance is OutputPane) 46 | return _instance; 47 | 48 | _instance = await CreatePaneAsync(); 49 | return _instance; 50 | } 51 | 52 | public async Task LogTextAsync(string text, CancellationToken token) 53 | { 54 | try 55 | { 56 | var pane = await GetPaneAsync(token); 57 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(token); 58 | pane.OutputStringThreadSafe(text + Environment.NewLine); 59 | } 60 | catch (Exception ex) 61 | { 62 | Trace.WriteLine(text); 63 | Trace.WriteLine("Logging error:"); 64 | Trace.WriteLine(ex); 65 | } 66 | } 67 | 68 | public async Task BringToFrontAsync(CancellationToken token) 69 | { 70 | try 71 | { 72 | var pane = await GetPaneAsync(token); 73 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(token); 74 | pane.Activate(); 75 | 76 | } 77 | catch (Exception ex) 78 | { 79 | Trace.WriteLine(ex); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/PredefinedCommandHandlerNames.cs: -------------------------------------------------------------------------------- 1 | namespace FantomasVs 2 | { 3 | 4 | internal static class PredefinedCommandHandlerNames 5 | { 6 | /// 7 | /// Command handler name for Automatic Pair Completion 8 | /// 9 | /// 10 | public const string AutomaticCompletion = "Automatic Pair Completion Command Handler"; 11 | 12 | /// 13 | /// Command handler name for Automatic Line Ender 14 | /// 15 | /// 16 | public const string AutomaticLineEnder = "Automatic Line Ender Command Handler"; 17 | 18 | /// 19 | /// Command handler name for Change Signature. 20 | /// 21 | public const string ChangeSignature = "Change Signature"; 22 | 23 | /// 24 | /// Command handler name for Class View. 25 | /// 26 | public const string ClassView = "Class View"; 27 | 28 | /// 29 | /// Command handler name for Comment Selection. 30 | /// 31 | /// 32 | public const string CommentSelection = "Comment Selection Command Handler"; 33 | 34 | /// 35 | /// Command handler name for Commit. 36 | /// 37 | /// 38 | public const string Commit = "Commit Command Handler"; 39 | 40 | /// 41 | /// Command handler name for Documentation Comments. 42 | /// 43 | public const string DocumentationComments = "Documentation Comments Command Handler"; 44 | 45 | /// 46 | /// Command handler name for Encapsulate Field. 47 | /// 48 | public const string EncapsulateField = nameof(EncapsulateField); 49 | 50 | /// 51 | /// Command handler name for End Construct. 52 | /// 53 | public const string EndConstruct = "End Construct Command Handler"; 54 | 55 | /// 56 | /// Command handler name for Event Hookup. 57 | /// 58 | public const string EventHookup = "Event Hookup Command Handler"; 59 | 60 | /// 61 | /// Command handler name for Extract Interface 62 | /// 63 | public const string ExtractInterface = "Extract Interface Command Handler"; 64 | 65 | /// 66 | /// Command handler name for Extract Method 67 | /// 68 | public const string ExtractMethod = "Extract Method Command Handler"; 69 | 70 | /// 71 | /// Command handler name for Find References. 72 | /// 73 | public const string FindReferences = "Find References Command Handler"; 74 | 75 | /// 76 | /// Command handler name for Format Document. 77 | /// 78 | public const string FormatDocument = "Format Document Command Handler"; 79 | 80 | /// 81 | /// Command handler name for Go to Base. 82 | /// 83 | public const string GoToBase = "Go To Base Command Handler"; 84 | 85 | /// 86 | /// Command handler name for Go to Definition. 87 | /// 88 | public const string GoToDefinition = "Go To Definition Command Handler"; 89 | 90 | /// 91 | /// Command handler name for Go to Implementation. 92 | /// 93 | public const string GoToImplementation = "Go To Implementation Command Handler"; 94 | 95 | /// 96 | /// Command handler name for Go to Adjacent Member. 97 | /// 98 | public const string GoToAdjacentMember = "Go To Adjacent Member Command Handler"; 99 | 100 | /// 101 | /// Command handler name for Indent. 102 | /// 103 | public const string Indent = "Indent Command Handler"; 104 | 105 | /// 106 | /// Command handler name for Navigate to Highlighted Reference. 107 | /// 108 | public const string NavigateToHighlightedReference = "Navigate to Highlighted Reference Command Handler"; 109 | 110 | /// 111 | /// Command handler name for Organize Document. 112 | /// 113 | public const string OrganizeDocument = "Organize Document Command Handler"; 114 | 115 | /// 116 | /// Command handler name for Quick Info. 117 | /// 118 | public const string QuickInfo = "Quick Info Command Handler"; 119 | 120 | /// 121 | /// Command handler name for Rename. 122 | /// 123 | public const string Rename = "Rename Command Handler"; 124 | 125 | /// 126 | /// Command handler name for Rename Tracking cancellation. 127 | /// 128 | public const string RenameTrackingCancellation = "Rename Tracking Cancellation Command Handler"; 129 | 130 | /// 131 | /// Command handler name for a Signature Help command handler executing before . 132 | /// 133 | public const string SignatureHelpBeforeCompletion = "Signature Help Before Completion Command Handler"; 134 | 135 | /// 136 | /// Command handler name for a Signature Help command handler executing after . 137 | /// 138 | public const string SignatureHelpAfterCompletion = "Signature Help After Completion Command Handler"; 139 | 140 | /// 141 | /// Command handler name for Toggle Block Comments. 142 | /// 143 | /// 144 | public const string ToggleBlockComment = "Toggle Block Comment Command Handler"; 145 | 146 | /// 147 | /// Command handler name for Toggle Line Comments. 148 | /// 149 | /// 150 | public const string ToggleLineComment = "Toggle Line Comment Command Handler"; 151 | 152 | /// 153 | /// Command handler name for Paste Content in Interactive Format. 154 | /// 155 | public const string InteractivePaste = "Interactive Paste Command Handler"; 156 | 157 | /// 158 | /// Command handler name for Paste in Paste Tracking. 159 | /// 160 | public const string PasteTrackingPaste = "Paste Tracking Paste Command Handler"; 161 | 162 | /// 163 | /// Command handler name for Edit and Continue file save handler. 164 | /// 165 | public const string EditAndContinueFileSave = "Edit and Continue Save File Handler"; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/FantomasVs.Shared/Theme.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Media; 6 | 7 | namespace FantomasVs 8 | { 9 | public static class Theme 10 | { 11 | public static string Background => (string) VsBrushes.ToolWindowBackgroundKey ?? "White"; 12 | public static string Foreground => (string) VsBrushes.ToolWindowTextKey ?? "Black"; 13 | public static string ButtonFace => (string) VsBrushes.ButtonFaceKey ?? "White"; 14 | public static string ButtonText => (string) VsBrushes.ButtonTextKey ?? "Black"; 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2019/FantomasVs.VS2019.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | Debug 11 | AnyCPU 12 | 2.0 13 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | {37577282-1289-40DB-AD3D-24499BD09DAE} 15 | Library 16 | Properties 17 | 9.0 18 | en 19 | FantomasVs 20 | FantomasVs 21 | v4.8 22 | true 23 | true 24 | true 25 | false 26 | false 27 | true 28 | true 29 | Program 30 | $(DevEnvDir)devenv.exe 31 | /rootsuffix Exp 32 | 33 | 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | win 50 | 51 | 52 | 53 | 54 | 55 | 56 | Designer 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 0.9.0 74 | 75 | 76 | 1.7.1 77 | 78 | 79 | 0.13.0 80 | 81 | 82 | 6.0.3 83 | 84 | 85 | compile; build; native; contentfiles; analyzers; buildtransitive 86 | 87 | 88 | runtime; build; native; contentfiles; analyzers; buildtransitive 89 | 90 | 91 | 16.2.29116.78 92 | 93 | 94 | 6.0.0 95 | 96 | 97 | 98 | 99 | License.txt 100 | true 101 | 102 | 103 | logo.png 104 | true 105 | 106 | 107 | ReleaseNotes.html 108 | true 109 | 110 | 111 | 112 | 113 | 114 | FantomasStable 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2019/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FantomasVs")] 9 | [assembly: AssemblyDescription("F# Formatter Extension for Visual Studio")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("asti")] 12 | [assembly: AssemblyProduct("FantomasVs")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("0.2.0.0")] 33 | [assembly: AssemblyFileVersion("0.2.0.0")] 34 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2019/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | F# Formatting 6 | F# source code formatting using Fantomas. 7 | https://github.com/deviousasti/fsharp-formatting-for-vs 8 | License.txt 9 | ReleaseNotes.html 10 | logo.png 11 | logo.png 12 | fsharp, formatting, fantomas, source, beautify 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2019/template.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | F# Formatting 6 | F# source code formatting using Fantomas. 7 | Built against {{latestTag}} stable 8 | https://github.com/deviousasti/fsharp-formatting-for-vs 9 | License.txt 10 | ReleaseNotes.html 11 | logo.png 12 | logo.png 13 | fsharp, formatting, fantomas, source, beautify 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2022/FantomasVs.VS2022.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | Debug 11 | AnyCPU 12 | 2.0 13 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5} 15 | Library 16 | Properties 17 | 9.0 18 | en 19 | FantomasVs 20 | FantomasVs 21 | v4.8 22 | true 23 | true 24 | true 25 | false 26 | false 27 | true 28 | true 29 | Program 30 | $(DevEnvDir)devenv.exe 31 | /rootsuffix Exp 32 | 33 | 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | 50 | 51 | 52 | 53 | 54 | 55 | Designer 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 0.9.0 73 | 74 | 75 | 1.7.1 76 | 77 | 78 | 0.13.0 79 | 80 | 81 | 6.0.3 82 | 83 | 84 | 6.0.0 85 | 86 | 87 | compile; build; native; contentfiles; analyzers; buildtransitive 88 | 89 | 90 | runtime; build; native; contentfiles; analyzers; buildtransitive 91 | all 92 | 93 | 94 | 95 | 96 | ReleaseNotes.html 97 | true 98 | 99 | 100 | License.txt 101 | true 102 | 103 | 104 | logo.png 105 | true 106 | 107 | 108 | 109 | 110 | 111 | FantomasStable 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2022/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FantomasVs.VS2022")] 9 | [assembly: AssemblyDescription("F# Formatter Extension for Visual Studio")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("asti")] 12 | [assembly: AssemblyProduct("FantomasVs")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("0.2.0.0")] 33 | [assembly: AssemblyFileVersion("0.2.0.0")] 34 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2022/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | F# Formatting 6 | F# source code formatting using Fantomas. 7 | https://github.com/deviousasti/fsharp-formatting-for-vs 8 | License.txt 9 | ReleaseNotes.html 10 | logo.png 11 | logo.png 12 | fsharp, formatting, fantomas, source, beautify 13 | 14 | 15 | 16 | amd64 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/FantomasVs.VS2022/template.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | F# Formatting 6 | F# source code formatting using Fantomas. 7 | Built against {{latestTag}} stable 8 | https://github.com/deviousasti/fsharp-formatting-for-vs 9 | License.txt 10 | ReleaseNotes.html 11 | logo.png 12 | logo.png 13 | fsharp, formatting, fantomas, source, beautify 14 | 15 | 16 | 17 | amd64 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/FantomasVs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32126.317 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FantomasVs.VS2022", "FantomasVs.VS2022\FantomasVs.VS2022.csproj", "{61BFDC11-A5E1-4C8D-952F-45267220D8B5}" 7 | EndProject 8 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "FantomasVs.Shared", "FantomasVs.Shared\FantomasVs.Shared.shproj", "{B7A936CA-E24E-4EA6-9571-1373C6E44614}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FantomasVs.VS2019", "FantomasVs.VS2019\FantomasVs.VS2019.csproj", "{37577282-1289-40DB-AD3D-24499BD09DAE}" 11 | EndProject 12 | Global 13 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 14 | FantomasVs.Shared\FantomasVs.Shared.projitems*{37577282-1289-40db-ad3d-24499bd09dae}*SharedItemsImports = 4 15 | FantomasVs.Shared\FantomasVs.Shared.projitems*{61bfdc11-a5e1-4c8d-952f-45267220d8b5}*SharedItemsImports = 4 16 | FantomasVs.Shared\FantomasVs.Shared.projitems*{b7a936ca-e24e-4ea6-9571-1373c6e44614}*SharedItemsImports = 13 17 | EndGlobalSection 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Debug|x86 = Debug|x86 21 | Release|Any CPU = Release|Any CPU 22 | Release|x86 = Release|x86 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Debug|x86.ActiveCfg = Debug|x86 28 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Debug|x86.Build.0 = Debug|x86 29 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Release|x86.ActiveCfg = Release|x86 32 | {61BFDC11-A5E1-4C8D-952F-45267220D8B5}.Release|x86.Build.0 = Release|x86 33 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Debug|x86.ActiveCfg = Debug|Any CPU 36 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Debug|x86.Build.0 = Debug|Any CPU 37 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Release|x86.ActiveCfg = Release|Any CPU 40 | {37577282-1289-40DB-AD3D-24499BD09DAE}.Release|x86.Build.0 = Release|Any CPU 41 | EndGlobalSection 42 | GlobalSection(SolutionProperties) = preSolution 43 | HideSolutionNode = FALSE 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {0039EA05-B140-4301-8B82-535FB9B5395C} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /src/ReleaseNotes.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/fantomas-for-vs/4ad91bca5e72d4fcdef395f6e186b41866367a7e/src/ReleaseNotes.html -------------------------------------------------------------------------------- /src/Resources/License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 Asti 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /src/Resources/ReleaseNotes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 92 |

Release Notes

93 |

1.3.0

94 |
    95 |
  • Add initial support for Fantomas cursor
  • 96 |
  • Upgrade Fantomas.Client to 0.7.0 (#51)
  • 97 |
98 |

1.2.0

99 |
    100 |
  • Fix dotnet tool install name and fantomas docs link (#41) thanks to @AkosLukacs
  • 101 |
  • Fix broken documentation links (#42)
  • 102 |
  • Upgrade Fantomas.Client to 0.7.0 (#42)
  • 103 |
  • Upgrade editorconfig to 0.13 (#42)
  • 104 |
105 |

1.1.0

106 |
    107 |
  • Improved logging and better diagnostics
  • 108 |
  • Update Fantomas.Client to 0.5.4
  • 109 |
110 |

1.0

111 |
    112 |
  • Use Fantomas.Client which supports installing and using Fantomas as a dotnet tools instead of being bundled with the extension
  • 113 |
114 |

0.9.4

115 |
    116 |
  • Update Fantomas to 4.5.8
  • 117 |
118 |

0.9.3

119 |
    120 |
  • Update Fantomas to 4.5.5
  • 121 |
122 |

0.9.2

123 |
    124 |
  • Update Fantomas to 4.5.4
  • 125 |
126 |

0.9.1

127 |
    128 |
  • Update stable Fantomas to 4.5.1
  • 129 |
  • Update latest Fantomas to 4.5.1
  • 130 |
  • Add 'Always place bar in front of discriminated union' option
  • 131 |
132 |

0.9

133 |
    134 |
  • Update to Fantomas to 4.5 alpha 17
  • 135 |
  • Add guard to diff algorithm
  • 136 |
137 |

0.8.4

138 |
    139 |
  • Implement diff shrinking for minimal edit surface
  • 140 |
141 |

0.8.3

142 |
    143 |
  • Unix line-endings supported with diff
  • 144 |
  • Implement line-ending agnostic chunker
  • 145 |
146 |

0.8.2

147 |
    148 |
  • Update stable Fantomas to 4.4.0
  • 149 |
  • Update latest to 4.5.0 alpha
  • 150 |
151 |

0.8.1

152 |
    153 |
  • Formatting defaults to stable version
  • 154 |
  • Update Fantomas to 4.4.0-beta-008
  • 155 |
156 |

0.8

157 |
    158 |
  • Change project build structure
  • 159 |
  • Support both latest (bleeding edge) and stable versions configurable by an option
  • 160 |
  • Update Fantomas to 4.4.0-beta-003
  • 161 |
162 |

0.7.3

163 |
    164 |
  • Add options to allow to not commit changes caused by format-on-save
  • 165 |
166 |

0.7.2

167 |
    168 |
  • Format on Save forces save if formatting results in a change
  • 169 |
  • Update Fantomas to 4.4.0 alpha
  • 170 |
  • Update to FCS 38.0.2
  • 171 |
172 |

0.7.1

173 |
    174 |
  • Fantomas Bugfix release
  • 175 |
  • Fantomas 4.3
  • 176 |
177 |

0.7

178 |
    179 |
  • Built against Fantomas 4.3 alpha
  • 180 |
  • Add support for line-ending options (and more)
  • 181 |
182 |

0.6

183 |
    184 |
  • Update to FCS 38
  • 185 |
  • Built against Fantomas 4.2
  • 186 |
187 |

0.5

188 |
    189 |
  • Support MultilineFormatter selection and additional options
  • 190 |
  • Built against Fantomas late September release
  • 191 |
192 |

0.4.6

193 |
    194 |
  • Built against Fantomas 4.1.1 stable
  • 195 |
196 |

0.4.5

197 |
    198 |
  • Built against Fantomas 4.1 September release
  • 199 |
200 |

0.4.4

201 |
    202 |
  • Fantomas 4.0.0 stable August release
  • 203 |
  • Format selection in Fantomas instead of isolated selection (still sensitive to whitespace)
  • 204 |
205 |

0.4.3

206 |
    207 |
  • Moved to FCS 37.0
  • 208 |
  • Built against 4.0.0 beta-004
  • 209 |
210 |

0.4.2

211 |
    212 |
  • Built against 4.0.0 beta-002
  • 213 |
  • Directly built for net48, no ILRepack
  • 214 |
215 |

0.4.1

216 |
    217 |
  • Built against 4.0.0 beta-001
  • 218 |
  • Upgrade vs build tools
  • 219 |
220 |

0.4

221 |
    222 |
  • Add MIT license
  • 223 |
  • Built against 4.0.0 alpha-013
  • 224 |
225 |

0.3

226 |
    227 |
  • Add support for .editorconfig
  • 228 |
  • Falls back to Visual Stuio configuration if no .editorconfig settings are found
  • 229 |
  • Built against 4.0.0 alpha (17bfa28ad)
  • 230 |
231 |

0.2

232 |
    233 |
  • Built against 4.0.0 alpha (28ed449c)
  • 234 |
  • Update format settings in VS config
  • 235 |
236 |

0.1

237 |
    238 |
  • Initial Release
  • 239 |
  • Built against 3.0.0
  • 240 |
  • Document Format
  • 241 |
  • Selection Format
  • 242 |
  • Format on Save
  • 243 |
  • Diff format
  • 244 |
245 |
295 | 296 | -------------------------------------------------------------------------------- /src/Resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/fantomas-for-vs/4ad91bca5e72d4fcdef395f6e186b41866367a7e/src/Resources/logo.png --------------------------------------------------------------------------------