diff --git a/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs b/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs index b775977ceb8b0..4b49ddcb28b6d 100644 --- a/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs +++ b/src/EditorFeatures/CSharp/ConvertNamespace/ConvertNamespaceCommandHandler.cs @@ -151,8 +151,7 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, if (!ConvertNamespaceAnalysis.CanOfferUseFileScoped(s_optionSet, root, namespaceDecl, forAnalyzer: true, LanguageVersion.CSharp10)) return default; - var formattingOptions = SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); - var (converted, semicolonSpan) = ConvertNamespaceTransform.ConvertNamespaceDeclarationAsync(document, namespaceDecl, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var (converted, semicolonSpan) = ConvertNamespaceTransform.ConvertNamespaceDeclarationAsync(document, namespaceDecl, cancellationToken).WaitAndGetResult(cancellationToken); var text = converted.GetTextSynchronously(cancellationToken); return (text, semicolonSpan); } diff --git a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs index de54c6c2ef306..ab1bd395c9d52 100644 --- a/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/CSharp/DocumentationComments/DocumentationCommentCommandHandler.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Text.Operations; @@ -21,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.DocumentationComments [Name(PredefinedCommandHandlerNames.DocumentationComments)] [Order(After = PredefinedCommandHandlerNames.Rename)] [Order(After = PredefinedCompletionNames.CompletionCommandHandler)] - internal sealed class DocumentationCommentCommandHandler + internal class DocumentationCommentCommandHandler : AbstractDocumentationCommentCommandHandler { [ImportingConstructor] @@ -29,9 +28,8 @@ internal sealed class DocumentationCommentCommandHandler public DocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, - IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) - : base(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + IEditorOperationsFactoryService editorOperationsFactoryService) + : base(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService) { } diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs index c3d80c50fff74..7429ddfdb13e4 100644 --- a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs @@ -97,10 +97,9 @@ SyntaxKind.InterpolatedSingleLineRawStringStartToken or return false; } - var indentationOptions = _globalOptions.GetIndentationOptionsAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); - var indentation = token.GetPreferredIndentation(document, indentationOptions, cancellationToken); + var indentation = token.GetPreferredIndentation(document, cancellationToken); - var newLine = indentationOptions.FormattingOptions.NewLine; + var newLine = document.Project.Solution.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); using var transaction = CaretPreservingEditTransaction.TryCreate( CSharpEditorResources.Split_string, textView, _undoHistoryRegistry, _editorOperationsFactoryService); diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs index 105b872f0a785..38d70b2805397 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -121,12 +120,12 @@ private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, int posi } // TODO: read option from textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) - var options = _globalOptions.GetIndentationOptionsAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + var indentStyle = document.Project.Solution.Options.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp); using var transaction = CaretPreservingEditTransaction.TryCreate( CSharpEditorResources.Split_string, textView, _undoHistoryRegistry, _editorOperationsFactoryService); - var splitter = StringSplitter.TryCreate(document, position, options, useTabs, tabSize, cancellationToken); + var splitter = StringSplitter.TryCreate(document, position, useTabs, tabSize, indentStyle, cancellationToken); if (splitter?.TrySplit(out var newDocument, out var newPosition) != true) { return false; diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs index 96153086229fa..d9a223fec282c 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs @@ -1117,12 +1117,14 @@ public void X() } }"; - using var session = CreateSession(code); + var optionSet = new Dictionary + { + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + }; + using var session = CreateSession(code, optionSet); Assert.NotNull(session); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); - CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1145,11 +1147,13 @@ public class C1 { } }"; - using var session = CreateSession(code); + var optionSet = new Dictionary + { + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } + }; + using var session = CreateSession(code, optionSet); Assert.NotNull(session); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None); - CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); } @@ -1178,11 +1182,13 @@ public class C1 } }"; - using var session = CreateSession(code); + var optionSet = new Dictionary + { + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + }; + using var session = CreateSession(code, optionSet); Assert.NotNull(session); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); - CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); @@ -1219,11 +1225,13 @@ public class C1 } }"; - using var session = CreateSession(code); + var optionSet = new Dictionary + { + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + }; + using var session = CreateSession(code, optionSet); Assert.NotNull(session); - session.Workspace.GlobalOptions.SetGlobalOption(new OptionKey(FormattingOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block); - CheckStart(session.Session); Assert.Equal(expected, session.Session.SubjectBuffer.CurrentSnapshot.GetText()); diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index 95a373678ce01..65149d894dba2 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -34,9 +34,9 @@ private static Dictionary SmartIndentButDoNotFormatWhileTypi { return new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Smart }, - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false }, - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Smart }, + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, }; } @@ -1070,11 +1070,11 @@ class C1 class C1 { }"; - var globalOptions = new Dictionary - { - { new OptionKey2(AutoFormattingOptionsStorage.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } - }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + var optionSet = new Dictionary + { + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } + }; + AssertFormatAfterTypeChar(code, expected, optionSet); } [WpfFact] @@ -1101,12 +1101,12 @@ class C } "; - var globalOptions = new Dictionary + var optionSet = new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false } }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + AssertFormatAfterTypeChar(code, expected, optionSet); } [WpfFact] @@ -1133,12 +1133,12 @@ class C } "; - var globalOptions = new Dictionary + var optionSet = new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + AssertFormatAfterTypeChar(code, expected, optionSet); } [WorkItem(5873, "https://github.com/dotnet/roslyn/issues/5873")] @@ -1165,12 +1165,12 @@ static void Main() } }"; - var globalOptions = new Dictionary + var optionSet = new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + AssertFormatAfterTypeChar(code, expected, optionSet); } [WorkItem(5873, "https://github.com/dotnet/roslyn/issues/5873")] @@ -1223,12 +1223,12 @@ class C } "; - var globalOptions = new Dictionary + var optionSet = new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnSemicolon, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, LanguageNames.CSharp), false } }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + AssertFormatAfterTypeChar(code, expected, optionSet); } [WpfFact] @@ -1255,12 +1255,12 @@ class C } "; - var globalOptions = new Dictionary + var optionSet = new Dictionary { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; - AssertFormatAfterTypeChar(code, expected, globalOptions); + AssertFormatAfterTypeChar(code, expected, optionSet); } [WpfFact, WorkItem(4435, "https://github.com/dotnet/roslyn/issues/4435")] @@ -2289,16 +2289,18 @@ class Test Assert.Single(annotatedTrivia); } - private static void AssertFormatAfterTypeChar(string code, string expected, Dictionary globalOptions = null) + private static void AssertFormatAfterTypeChar(string code, string expected, Dictionary changedOptionSet = null) { using var workspace = TestWorkspace.CreateCSharp(code); - if (globalOptions != null) + if (changedOptionSet != null) { - var options = workspace.GlobalOptions; - foreach (var entry in globalOptions) + var options = workspace.Options; + foreach (var entry in changedOptionSet) { - options.SetGlobalOption((OptionKey)entry.Key, entry.Value); + options = options.WithChangedOption(entry.Key, entry.Value); } + + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(options)); } var subjectDocument = workspace.Documents.Single(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs index c732f951c2094..ab19697d14108 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs @@ -82,10 +82,7 @@ private static async Task TokenFormatWorkerAsync(TestWorkspace workspace, ITextB var rules = formattingRuleProvider.CreateRule(document, position).Concat(Formatter.GetDefaultFormattingRules(document)); - var options = new IndentationOptions( - await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None).ConfigureAwait(false), - AutoFormattingOptions.Default); - + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); var formatter = new CSharpSmartTokenFormatter(options, rules, root); var changes = await formatter.FormatTokenAsync(workspace.Services, token, CancellationToken.None); diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs index 27fcbecb9d42e..f8d087ef82fef 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Indentation; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; @@ -1502,17 +1501,21 @@ private static async Task AssertIndentUsingSmartTokenFormatterAsync( // create tree service using var workspace = TestWorkspace.CreateCSharp(code); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); + var hostdoc = workspace.Documents.First(); + var buffer = hostdoc.GetTextBuffer(); + var snapshot = buffer.CurrentSnapshot; var line = snapshot.GetLineFromLineNumber(indentationLine); + var document = workspace.CurrentSolution.GetDocument(hostdoc.Id); var root = (await document.GetSyntaxRootAsync()) as CompilationUnitSyntax; - var options = new IndentationOptions( - CSharpSyntaxFormattingOptions.Default.With(useTabs: useTabs, tabSize: 4, indentationSize: 4), - AutoFormattingOptions.Default); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); Assert.True( CSharpIndentationService.ShouldUseSmartTokenFormatterInsteadOfIndenter( @@ -1523,7 +1526,7 @@ private static async Task AssertIndentUsingSmartTokenFormatterAsync( Assert.Equal(expectedIndentation.Value, actualIndentation); } - private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( + private static async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( string code, int indentationLine, int? expectedIndentation, @@ -1533,7 +1536,7 @@ private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( await AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(code.Replace(" ", "\t"), indentationLine, expectedIndentation, useTabs: true, indentStyle).ConfigureAwait(false); } - private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( + private static async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( string code, int indentationLine, int? expectedIndentation, @@ -1542,7 +1545,9 @@ private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( { // create tree service using var workspace = TestWorkspace.CreateCSharp(code); - + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); var hostdoc = workspace.Documents.First(); var buffer = hostdoc.GetTextBuffer(); var snapshot = buffer.CurrentSnapshot; @@ -1553,16 +1558,14 @@ private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync( var root = (await document.GetSyntaxRootAsync()) as CompilationUnitSyntax; - var options = new IndentationOptions( - CSharpSyntaxFormattingOptions.Default.With(useTabs: useTabs, tabSize: 4, indentationSize: 4), - new AutoFormattingOptions(IndentStyle: indentStyle)); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); Assert.False( CSharpIndentationService.ShouldUseSmartTokenFormatterInsteadOfIndenter( Formatter.GetDefaultFormattingRules(document), root, line.AsTextLine(), options, out _)); - TestIndentation(workspace, indentationLine, expectedIndentation, indentStyle, useTabs); + TestIndentation(workspace, indentationLine, expectedIndentation); } } } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs index 79a0a56823f20..eaac1999653f6 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; using Roslyn.Test.Utilities; @@ -3014,10 +3013,8 @@ private static void AssertSmartIndentInProjection( using var workspace = TestWorkspace.CreateCSharp(markup, parseOptions: option, composition: s_compositionWithTestFormattingRules); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); - - workspace.GlobalOptions.SetGlobalOption(new OptionKey(AutoFormattingOptionsStorage.SmartIndent, LanguageNames.CSharp), indentStyle); - var subjectDocument = workspace.Documents.Single(); var projectedDocument = @@ -3032,11 +3029,11 @@ private static void AssertSmartIndentInProjection( TestIndentation( point.Value, expectedIndentation, - projectedDocument.GetTextView(), subjectDocument, workspace.GlobalOptions); + projectedDocument.GetTextView(), subjectDocument); } } - private void AssertSmartIndent( + private static void AssertSmartIndent( string code, int indentationLine, int? expectedIndentation, @@ -3047,7 +3044,7 @@ private void AssertSmartIndent( AssertSmartIndent(code.Replace(" ", "\t"), indentationLine, expectedIndentation, useTabs: true, options, indentStyle); } - private void AssertSmartIndent( + private static void AssertSmartIndent( string code, int indentationLine, int? expectedIndentation, @@ -3063,11 +3060,14 @@ private void AssertSmartIndent( { using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option); - TestIndentation(workspace, indentationLine, expectedIndentation, indentStyle, useTabs); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); + TestIndentation(workspace, indentationLine, expectedIndentation); } } - private void AssertSmartIndent( + private static void AssertSmartIndent( string code, int? expectedIndentation, CSharpParseOptions options = null, @@ -3077,7 +3077,7 @@ private void AssertSmartIndent( AssertSmartIndent(code.Replace(" ", "\t"), expectedIndentation, useTabs: true, options, indentStyle); } - private void AssertSmartIndent( + private static void AssertSmartIndent( string code, int? expectedIndentation, bool useTabs, @@ -3092,9 +3092,12 @@ private void AssertSmartIndent( { using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); var wpfTextView = workspace.Documents.First().GetTextView(); var line = wpfTextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(wpfTextView.Caret.Position.BufferPosition).LineNumber; - TestIndentation(workspace, line, expectedIndentation, indentStyle, useTabs); + TestIndentation(workspace, line, expectedIndentation); } } } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs index 19104a2b4ef3a..3f5ef74ec4eaf 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Indentation; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; @@ -3571,6 +3570,9 @@ private static async Task AutoFormatOnMarkerAsync(string initialMarkup, string e { using var workspace = TestWorkspace.CreateCSharp(initialMarkup); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(FormattingOptions2.UseTabs, LanguageNames.CSharp, useTabs))); + var testDocument = workspace.Documents.Single(); var buffer = testDocument.GetTextBuffer(); var position = testDocument.CursorPosition.Value; @@ -3586,11 +3588,7 @@ private static async Task AutoFormatOnMarkerAsync(string initialMarkup, string e } Assert.Equal(tokenKind, endToken.Kind()); - - var options = new IndentationOptions( - CSharpSyntaxFormattingOptions.Default.With(useTabs: useTabs, tabSize: 4, indentationSize: 4), - AutoFormattingOptions.Default); - + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); var formatter = new CSharpSmartTokenFormatter(options, rules, root); var tokenRange = FormattingRangeHelper.FindAppropriateRange(endToken); diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index 5d5f47ef8dc61..c44723ac7b064 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -49,7 +48,8 @@ private static void TestWorker( using var workspace = TestWorkspace.CreateCSharp(inputMarkup); // TODO: set SmartIndent to textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) - workspace.GlobalOptions.SetGlobalOption(new OptionKey(AutoFormattingOptionsStorage.SmartIndent, LanguageNames.CSharp), indentStyle); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle))); if (useTabs && expectedOutputMarkup != null) { diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 31a906bee5b3b..62dcf63715945 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -12,9 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Indentation; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; @@ -35,6 +33,8 @@ internal partial class BraceCompletionSessionProvider // modified it little bit so that we can use it as base class. private class BraceCompletionSession : ForegroundThreadAffinitizedObject, IBraceCompletionSession { + #region Private Members + public char OpeningBrace { get; } public char ClosingBrace { get; } public ITrackingPoint OpeningPoint { get; private set; } @@ -45,26 +45,30 @@ private class BraceCompletionSession : ForegroundThreadAffinitizedObject, IBrace private readonly ITextUndoHistory _undoHistory; private readonly IEditorOperations _editorOperations; private readonly IBraceCompletionService _service; - private readonly IGlobalOptionService _globalOptions; + + #endregion + + #region Constructors public BraceCompletionSession( ITextView textView, ITextBuffer subjectBuffer, SnapshotPoint openingPoint, char openingBrace, char closingBrace, ITextUndoHistory undoHistory, IEditorOperationsFactoryService editorOperationsFactoryService, IBraceCompletionService service, - IGlobalOptionService globalOptions, IThreadingContext threadingContext) + IThreadingContext threadingContext) : base(threadingContext, assertIsForeground: true) { - TextView = textView; - SubjectBuffer = subjectBuffer; - OpeningBrace = openingBrace; - ClosingBrace = closingBrace; - ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingPoint.Position, PointTrackingMode.Positive); + this.TextView = textView; + this.SubjectBuffer = subjectBuffer; + this.OpeningBrace = openingBrace; + this.ClosingBrace = closingBrace; + this.ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingPoint.Position, PointTrackingMode.Positive); _undoHistory = undoHistory; _editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); _service = service; - _globalOptions = globalOptions; } + #endregion + #region IBraceCompletionSession Methods public void Start() @@ -123,10 +127,8 @@ private bool TryStart(CancellationToken cancellationToken) var contextAfterStart = GetBraceCompletionContext(); if (contextAfterStart != null) { - var document = contextAfterStart.Value.Document; - var indentationOptions = _globalOptions.GetIndentationOptionsAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); - - var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, indentationOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var options = IndentationOptions.FromDocumentAsync(contextAfterStart.Value.Document, cancellationToken).WaitAndGetResult(cancellationToken); + var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, options, cancellationToken).WaitAndGetResult(cancellationToken); if (changesAfterStart != null) { ApplyBraceCompletionResult(changesAfterStart.Value); @@ -284,8 +286,8 @@ public void PostReturn() return; } - var indentationOptions = _globalOptions.GetIndentationOptionsAsync(context.Value.Document, CancellationToken.None).WaitAndGetResult(CancellationToken.None); - var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, indentationOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var options = IndentationOptions.FromDocumentAsync(context.Value.Document, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, options, CancellationToken.None).WaitAndGetResult(CancellationToken.None); if (changesAfterReturn != null) { using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs index e89f809f20c3b..865562f5963e5 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; @@ -35,20 +34,17 @@ internal partial class BraceCompletionSessionProvider : ForegroundThreadAffiniti { private readonly ITextBufferUndoManagerProvider _undoManager; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public BraceCompletionSessionProvider( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, - IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + IEditorOperationsFactoryService editorOperationsFactoryService) : base(threadingContext) { _undoManager = undoManager; _editorOperationsFactoryService = editorOperationsFactoryService; - _globalOptions = globalOptions; } public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, char openingBrace, char closingBrace, out IBraceCompletionSession session) @@ -71,7 +67,7 @@ public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, cha session = new BraceCompletionSession( textView, openingPoint.Snapshot.TextBuffer, openingPoint, openingBrace, closingBrace, undoHistory, _editorOperationsFactoryService, - editorSession, _globalOptions, ThreadingContext); + editorSession, ThreadingContext); return true; } } diff --git a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs index 968f3e3a85fd2..feeaa42df39e2 100644 --- a/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs @@ -30,13 +30,11 @@ internal abstract class AbstractDocumentationCommentCommandHandler : private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IGlobalOptionService _globalOptions; protected AbstractDocumentationCommentCommandHandler( IUIThreadOperationExecutor uiThreadOperationExecutor, ITextUndoHistoryRegistry undoHistoryRegistry, - IEditorOperationsFactoryService editorOperationsFactoryService, - IGlobalOptionService globalOptions) + IEditorOperationsFactoryService editorOperationsFactoryService) { Contract.ThrowIfNull(uiThreadOperationExecutor); Contract.ThrowIfNull(undoHistoryRegistry); @@ -45,7 +43,6 @@ protected AbstractDocumentationCommentCommandHandler( _uiThreadOperationExecutor = uiThreadOperationExecutor; _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; - _globalOptions = globalOptions; } protected abstract string ExteriorTriviaText { get; } @@ -73,7 +70,7 @@ private static void ApplySnippet(DocumentationCommentSnippet snippet, ITextBuffe textView.TryMoveCaretToAndEnsureVisible(subjectBuffer.CurrentSnapshot.GetPoint(replaceSpan.Start + snippet.CaretOffset)); } - private bool CompleteComment( + private static bool CompleteComment( ITextBuffer subjectBuffer, ITextView textView, Func getSnippetAction, @@ -95,7 +92,7 @@ private bool CompleteComment( var syntaxTree = document.GetRequiredSyntaxTreeSynchronously(cancellationToken); var text = syntaxTree.GetText(cancellationToken); var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); - var options = _globalOptions.GetDocumentationCommentOptions(documentOptions); + var options = DocumentationCommentOptions.From(documentOptions); // Apply snippet in reverse order so that the first applied snippet doesn't affect span of next snippets. var snapshots = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer).OrderByDescending(s => s.Span.Start); @@ -338,7 +335,7 @@ private void InsertExteriorTriviaIfNeeded(IDocumentationCommentSnippetService se } var documentOptions = document.GetOptionsAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); - var options = _globalOptions.GetDocumentationCommentOptions(documentOptions); + var options = DocumentationCommentOptions.From(documentOptions); var snippet = service.GetDocumentationCommentSnippetFromPreviousLine(options, currentLine, previousLine); if (snippet != null) diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs index b4c044bfa1918..6326622d89390 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Indentation; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript { @@ -35,16 +34,16 @@ public VSTypeScriptFormattingInteractionService(IVSTypeScriptFormattingInteracti public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch) => _implementation.SupportsFormattingOnTypedCharacter(document, ch); - public Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => _implementation.GetFormattingChangesAsync(document, textSpan, documentOptions: null, cancellationToken); + public Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) + => _implementation.GetFormattingChangesAsync(document, textSpan, documentOptions, cancellationToken); - public Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => _implementation.GetFormattingChangesOnPasteAsync(document, textSpan, documentOptions: null, cancellationToken); + public Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) + => _implementation.GetFormattingChangesOnPasteAsync(document, textSpan, documentOptions, cancellationToken); - public Task> GetFormattingChangesAsync(Document document, char typedChar, int position, IndentationOptions options, CancellationToken cancellationToken) - => _implementation.GetFormattingChangesAsync(document, typedChar, position, documentOptions: null, cancellationToken); + public Task> GetFormattingChangesAsync(Document document, char typedChar, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) + => _implementation.GetFormattingChangesAsync(document, typedChar, position, documentOptions, cancellationToken); - public Task> GetFormattingChangesOnReturnAsync(Document document, int position, CancellationToken cancellationToken) - => _implementation.GetFormattingChangesOnReturnAsync(document, position, documentOptions: null, cancellationToken); + public Task> GetFormattingChangesOnReturnAsync(Document document, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) + => _implementation.GetFormattingChangesOnReturnAsync(document, position, documentOptions, cancellationToken); } } diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs index 3bb866cb6e7bb..f64c7034ec5b5 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.Paste.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -72,8 +71,7 @@ private void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPos return; } - var services = solution.Workspace.Services; - var formattingRuleService = services.GetService(); + var formattingRuleService = solution.Workspace.Services.GetService(); if (formattingRuleService != null && formattingRuleService.ShouldNotFormatOrCommitOnPaste(document)) { return; @@ -87,10 +85,8 @@ private void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPos var trackingSpan = caretPosition.Value.Snapshot.CreateTrackingSpan(caretPosition.Value.Position, 0, SpanTrackingMode.EdgeInclusive); var span = trackingSpan.GetSpan(args.SubjectBuffer.CurrentSnapshot).Span.ToTextSpan(); - var formattingOptions = _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat: false, cancellationToken).WaitAndGetResult(cancellationToken); - var changes = formattingService.GetFormattingChangesOnPasteAsync( - document, span, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); + document, span, documentOptions: null, cancellationToken).WaitAndGetResult(cancellationToken); if (changes.IsEmpty) { return; diff --git a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs index 40ce24fdba0f1..5ea96bd45e286 100644 --- a/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs +++ b/src/EditorFeatures/Core/Formatting/FormatCommandHandler.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -45,7 +44,6 @@ internal partial class FormatCommandHandler : { private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; - private readonly IIndentationManagerService _indentationManager; private readonly IGlobalOptionService _globalOptions; public string DisplayName => EditorFeaturesResources.Automatic_Formatting; @@ -55,12 +53,10 @@ internal partial class FormatCommandHandler : public FormatCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, - IIndentationManagerService indentationManager, IGlobalOptionService globalOptions) { _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; - _indentationManager = indentationManager; _globalOptions = globalOptions; } @@ -71,8 +67,8 @@ private void Format(ITextView textView, Document document, TextSpan? selectionOp using (Logger.LogBlock(FunctionId.CommandHandler_FormatCommand, KeyValueLogMessage.Create(LogType.UserAction, m => m["Span"] = selectionOpt?.Length ?? -1), cancellationToken)) using (var transaction = CreateEditTransaction(textView, EditorFeaturesResources.Formatting)) { - var formattingOptions = _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat: true, cancellationToken).WaitAndGetResult(cancellationToken); - var changes = formattingService.GetFormattingChangesAsync(document, selectionOpt, formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var changes = formattingService.GetFormattingChangesAsync( + document, selectionOpt, documentOptions: null, cancellationToken).WaitAndGetResult(cancellationToken); if (changes.IsEmpty) { return; @@ -166,21 +162,19 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati return; } - textChanges = service.GetFormattingChangesOnReturnAsync(document, caretPosition.Value, cancellationToken).WaitAndGetResult(cancellationToken); + textChanges = service.GetFormattingChangesOnReturnAsync( + document, caretPosition.Value, documentOptions: null, cancellationToken).WaitAndGetResult(cancellationToken); } else if (args is TypeCharCommandArgs typeCharArgs) { - var autoFormattingOptions = _globalOptions.GetAutoFormattingOptions(document.Project.Language); - if (!service.SupportsFormattingOnTypedCharacter(document, autoFormattingOptions, typeCharArgs.TypedChar)) + var options = AutoFormattingOptions.From(document.Project); + if (!service.SupportsFormattingOnTypedCharacter(document, options, typeCharArgs.TypedChar)) { return; } - var formattingOptions = _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat: false, cancellationToken).WaitAndGetResult(cancellationToken); - var indentationOptions = new IndentationOptions(formattingOptions, autoFormattingOptions); - textChanges = service.GetFormattingChangesAsync( - document, typeCharArgs.TypedChar, caretPosition.Value, indentationOptions, cancellationToken).WaitAndGetResult(cancellationToken); + document, typeCharArgs.TypedChar, caretPosition.Value, documentOptions: null, cancellationToken).WaitAndGetResult(cancellationToken); } else { diff --git a/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs b/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs deleted file mode 100644 index 29030f0817f35..0000000000000 --- a/src/EditorFeatures/Core/Formatting/IndentationManagerExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.Formatting -{ - internal static class IndentationManagerExtensions - { - public static async Task GetInferredFormattingOptionsAsync(this IIndentationManagerService indentationManager, Document document, bool explicitFormat, CancellationToken cancellationToken) - { - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var snapshot = text.FindCorrespondingEditorTextSnapshot(); - - var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - if (snapshot == null) - { - return options; - } - - indentationManager.GetIndentation(snapshot.TextBuffer, explicitFormat, out var convertTabsToSpaces, out var tabSize, out var indentSize); - - return options.With( - useTabs: !convertTabsToSpaces, - indentationSize: indentSize, - tabSize: tabSize); - } - } -} diff --git a/src/EditorFeatures/Core/Indentation/EditorLayerInferredIndentationService.cs b/src/EditorFeatures/Core/Indentation/EditorLayerInferredIndentationService.cs new file mode 100644 index 0000000000000..3c80a220bc69e --- /dev/null +++ b/src/EditorFeatures/Core/Indentation/EditorLayerInferredIndentationService.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.VisualStudio.LanguageServices.Indentation +{ + [ExportWorkspaceService(typeof(IInferredIndentationService), ServiceLayer.Editor), Shared] + internal sealed class EditorLayerInferredIndentationService : IInferredIndentationService + { + private readonly IIndentationManagerService _indentationManagerService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public EditorLayerInferredIndentationService(IIndentationManagerService indentationManagerService) + { + _indentationManagerService = indentationManagerService; + } + + public async Task GetDocumentOptionsWithInferredIndentationAsync(Document document, bool explicitFormat, CancellationToken cancellationToken) + { + var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var snapshot = text.FindCorrespondingEditorTextSnapshot(); + + if (snapshot != null) + { + _indentationManagerService.GetIndentation(snapshot.TextBuffer, explicitFormat, out var convertTabsToSpaces, out var tabSize, out var indentSize); + + options = options.WithChangedOption(FormattingOptions.UseTabs, !convertTabsToSpaces) + .WithChangedOption(FormattingOptions.IndentationSize, indentSize) + .WithChangedOption(FormattingOptions.TabSize, tabSize); + } + + return options; + } + } +} diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs index 4a0861810e1a9..1059605bec8ed 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs @@ -25,7 +25,6 @@ using AsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; using VSCompletionItem = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem; -using Microsoft.CodeAnalysis.Indentation; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion { @@ -36,7 +35,6 @@ internal sealed class CommitManager : ForegroundThreadAffinitizedObject, IAsyncC private readonly RecentItemsManager _recentItemsManager; private readonly ITextView _textView; - private readonly IIndentationManagerService _indentationManager; private readonly IGlobalOptionService _globalOptions; public IEnumerable PotentialCommitCharacters @@ -55,18 +53,12 @@ public IEnumerable PotentialCommitCharacters } } - internal CommitManager( - ITextView textView, - RecentItemsManager recentItemsManager, - IThreadingContext threadingContext, - IIndentationManagerService indentationManager, - IGlobalOptionService globalOptions) + internal CommitManager(ITextView textView, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions, IThreadingContext threadingContext) : base(threadingContext) { _globalOptions = globalOptions; _recentItemsManager = recentItemsManager; _textView = textView; - _indentationManager = indentationManager; } /// @@ -289,11 +281,10 @@ private AsyncCompletionData.CommitResult Commit( if (currentDocument != null && formattingService != null) { - var formattingOptions = _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat: true, cancellationToken).WaitAndGetResult(cancellationToken); var spanToFormat = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive); var changes = formattingService.GetFormattingChangesAsync( - currentDocument, spanToFormat.Span.ToTextSpan(), formattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); - currentDocument.Project.Solution.Workspace.ApplyTextChanges(currentDocument.Id, changes, cancellationToken); + currentDocument, spanToFormat.Span.ToTextSpan(), documentOptions: null, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + currentDocument.Project.Solution.Workspace.ApplyTextChanges(currentDocument.Id, changes, CancellationToken.None); } } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs index 3aa7f2cf580b2..0e3bd7e6af515 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManagerProvider.cs @@ -21,20 +21,14 @@ internal class CommitManagerProvider : IAsyncCompletionCommitManagerProvider { private readonly IThreadingContext _threadingContext; private readonly RecentItemsManager _recentItemsManager; - private readonly IIndentationManagerService _indentationManager; private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CommitManagerProvider( - IThreadingContext threadingContext, - RecentItemsManager recentItemsManager, - IIndentationManagerService indentationManager, - IGlobalOptionService globalOptions) + public CommitManagerProvider(IThreadingContext threadingContext, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions) { _threadingContext = threadingContext; _recentItemsManager = recentItemsManager; - _indentationManager = indentationManager; _globalOptions = globalOptions; } @@ -45,7 +39,7 @@ public CommitManagerProvider( return null; } - return new CommitManager(textView, _recentItemsManager, _threadingContext, _indentationManager, _globalOptions); + return new CommitManager(textView, _recentItemsManager, _globalOptions, _threadingContext); } } } diff --git a/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs b/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs index 647423a2b3615..7e6395e17545d 100644 --- a/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs +++ b/src/EditorFeatures/Core/SmartIndent/SmartIndent.cs @@ -5,28 +5,21 @@ using System; using System.Threading; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent { internal partial class SmartIndent : ISmartIndent { private readonly ITextView _textView; - private readonly IGlobalOptionService _globalOptions; - public SmartIndent(ITextView textView, IGlobalOptionService globalOptions) - { - _textView = textView; - _globalOptions = globalOptions; - } + public SmartIndent(ITextView textView) + => _textView = textView ?? throw new ArgumentNullException(nameof(textView)); public int? GetDesiredIndentation(ITextSnapshotLine line) => GetDesiredIndentation(line, CancellationToken.None); @@ -50,8 +43,7 @@ public void Dispose() if (newService == null) return null; - var indentationOptions = _globalOptions.GetIndentationOptionsAsync(document, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); - var result = newService.GetIndentation(document, line.LineNumber, indentationOptions, cancellationToken); + var result = newService.GetIndentation(document, line.LineNumber, cancellationToken); return result.GetIndentation(_textView, line); } } diff --git a/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs b/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs index e8f1a12a740c8..91fa421930441 100644 --- a/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs +++ b/src/EditorFeatures/Core/SmartIndent/SmartIndentProvider.cs @@ -40,7 +40,7 @@ public ISmartIndent CreateSmartIndent(ITextView textView) return null; } - return new SmartIndent(textView, _globalOptions); + return new SmartIndent(textView); } } } diff --git a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs index 4daaf3a9f50d1..0f3190db3c2cd 100644 --- a/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/TestUtilities/AutomaticCompletion/AbstractAutomaticBraceCompletionTests.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.AutomaticCompletion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; diff --git a/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs b/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs index ffd9d7d86417e..565974ba4316b 100644 --- a/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs +++ b/src/EditorFeatures/TestUtilities/DocumentationComments/AbstractDocumentationCommentTests.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; @@ -127,12 +126,13 @@ private void Verify(string initialMarkup, string expectedMarkup, bool useTabs, b using (var workspace = CreateTestWorkspace(initialMarkup)) { var testDocument = workspace.Documents.Single(); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, testDocument.Project.Language), autoGenerateXmlDocComments); var options = workspace.Options; options = options.WithChangedOption(FormattingOptions.UseTabs, testDocument.Project.Language, useTabs); + options = options.WithChangedOption(DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration, testDocument.Project.Language, autoGenerateXmlDocComments); options = options.WithChangedOption(FormattingOptions.NewLine, testDocument.Project.Language, newLine); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(options)); setOptionsOpt?.Invoke(workspace); diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index 432ae717e94cc..c51a70e87b39a 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -66,8 +66,7 @@ private async Task TestCoreAsync(string testCode, string expected, (OptionKey var document = workspace.CurrentSolution.Projects.First().Documents.First(); var formattingService = document.GetRequiredLanguageService(); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None).ConfigureAwait(false); - var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, formattingOptions, CancellationToken.None); + var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, CancellationToken.None); var actual = await formattedDocument.GetTextAsync(); AssertEx.EqualOrDiff(expected, actual.ToString()); diff --git a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs index 3c5b3c66ea5eb..8907d93f80f28 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -47,8 +47,8 @@ protected CoreFormatterTestsBase(ITestOutputHelper output) protected abstract string GetLanguageName(); protected abstract SyntaxNode ParseCompilationUnit(string expected); - internal static void TestIndentation( - int point, int? expectedIndentation, ITextView textView, TestHostDocument subjectDocument, IGlobalOptionService globalOptions) + protected static void TestIndentation( + int point, int? expectedIndentation, ITextView textView, TestHostDocument subjectDocument) { var textUndoHistory = new Mock(); var editorOperationsFactory = new Mock(); @@ -58,25 +58,14 @@ internal static void TestIndentation( var snapshot = subjectDocument.GetTextBuffer().CurrentSnapshot; var indentationLineFromBuffer = snapshot.GetLineFromPosition(point); - var provider = new SmartIndent(textView, globalOptions); + var provider = new SmartIndent(textView); var actualIndentation = provider.GetDesiredIndentation(indentationLineFromBuffer); Assert.Equal(expectedIndentation, actualIndentation.Value); } - protected void TestIndentation( - TestWorkspace workspace, - int indentationLine, - int? expectedIndentation, - FormattingOptions.IndentStyle indentStyle, - bool useTabs) + protected static void TestIndentation(TestWorkspace workspace, int indentationLine, int? expectedIndentation) { - var language = GetLanguageName(); - workspace.GlobalOptions.SetGlobalOption(new OptionKey(AutoFormattingOptionsStorage.SmartIndent, language), indentStyle); - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingOptions2.UseTabs, language, useTabs))); - var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var bufferGraph = new Mock(MockBehavior.Strict); bufferGraph.Setup(x => x.MapUpToSnapshot(It.IsAny(), @@ -85,6 +74,7 @@ protected void TestIndentation( It.IsAny())) .Returns((p, m, a, s) => { + if (workspace.Services.GetService() is TestFormattingRuleFactoryServiceFactory.Factory factory && factory.BaseIndentation != 0 && factory.TextSpan.Contains(p.Position)) { var line = p.GetContainingLine(); @@ -103,7 +93,7 @@ protected void TestIndentation( textView.Setup(x => x.BufferGraph).Returns(bufferGraph.Object); textView.SetupGet(x => x.TextSnapshot.TextBuffer).Returns(projectionBuffer.Object); - var provider = new SmartIndent(textView.Object, workspace.GlobalOptions); + var provider = new SmartIndent(textView.Object); var indentationLineFromBuffer = snapshot.GetLineFromLineNumber(indentationLine); var actualIndentation = provider.GetDesiredIndentation(indentationLineFromBuffer); diff --git a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb index 395db41ad26b6..a312477816cfa 100644 --- a/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/DocumentationComments/DocumentationCommentCommandHandler.vb @@ -10,7 +10,6 @@ Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Utilities Imports Microsoft.CodeAnalysis.DocumentationComments -Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.DocumentationComments @@ -26,10 +25,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.DocumentationComments Public Sub New( uiThreadOperationExecutor As IUIThreadOperationExecutor, undoHistoryRegistry As ITextUndoHistoryRegistry, - editorOperationsFactoryService As IEditorOperationsFactoryService, - globalOptions As IGlobalOptionService) + editorOperationsFactoryService As IEditorOperationsFactoryService) - MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService, globalOptions) + MyBase.New(uiThreadOperationExecutor, undoHistoryRegistry, editorOperationsFactoryService) End Sub Protected Overrides ReadOnly Property ExteriorTriviaText As String diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb index f5889434f3474..66d92f0a3fde4 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb @@ -15,7 +15,6 @@ Imports Microsoft.CodeAnalysis.Internal.Log Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text -Imports Microsoft.VisualStudio.Text.Editor Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit @@ -29,13 +28,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End Function Private ReadOnly _globalOptions As IGlobalOptionService - Private ReadOnly _indentationManager As IIndentationManagerService - Public Sub New(globalOptions As IGlobalOptionService, indentationManager As IIndentationManagerService) + Public Sub New(globalOptions As IGlobalOptionService) _globalOptions = globalOptions - _indentationManager = indentationManager End Sub Public Sub CommitRegion(spanToFormat As SnapshotSpan, @@ -72,42 +69,36 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit End If ' create commit formatting cleanup provider that has line commit specific behavior - Dim formattingOptions = _indentationManager.GetInferredFormattingOptionsAsync(document, isExplicitFormat, cancellationToken).WaitAndGetResult(cancellationToken) + Dim inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(Of IInferredIndentationService)() + Dim documentOptions = inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, isExplicitFormat, cancellationToken).WaitAndGetResult(cancellationToken) + Dim formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language) Dim commitFormattingCleanup = GetCommitFormattingCleanupProvider( - document, - formattingOptions, - spanToFormat, - baseSnapshot, - baseTree, - dirtyRegion, - document.GetSyntaxTreeSynchronously(cancellationToken), - cancellationToken) + document, + formattingOptions, + spanToFormat, + baseSnapshot, baseTree, + dirtyRegion, + document.GetSyntaxTreeSynchronously(cancellationToken), + cancellationToken) Dim codeCleanups = CodeCleaner.GetDefaultProviders(document). WhereAsArray(s_codeCleanupPredicate). Concat(commitFormattingCleanup) - Dim cleanupService = document.GetRequiredLanguageService(Of ICodeCleanerService) - Dim finalDocument As Document If useSemantics OrElse isExplicitFormat Then - finalDocument = cleanupService.CleanupAsync( - document, - ImmutableArray.Create(textSpanToFormat), - formattingOptions, - codeCleanups, - cancellationToken).WaitAndGetResult(cancellationToken) + finalDocument = CodeCleaner.CleanupAsync(document, + textSpanToFormat, + codeCleanups, + cancellationToken).WaitAndGetResult(cancellationToken) Else Dim root = document.GetSyntaxRootSynchronously(cancellationToken) - - Dim newRoot = cleanupService.CleanupAsync( - root, - ImmutableArray.Create(textSpanToFormat), - formattingOptions, - document.Project.Solution.Workspace.Services, - codeCleanups, - cancellationToken).WaitAndGetResult(cancellationToken) - + Dim newRoot = CodeCleaner.CleanupAsync(root, + textSpanToFormat, + documentOptions, + document.Project.Solution.Workspace.Services, + codeCleanups, + cancellationToken).WaitAndGetResult(cancellationToken) If root Is newRoot Then finalDocument = document Else diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb index 04f17878100b7..48c82b27459ca 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartIndenterTests.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -2096,6 +2097,13 @@ End Module.Value End Sub #End Region + + + Public Sub TestSmartIndenterConstructorThrows1() + Assert.Throws(Of ArgumentNullException)( + Function() New SmartIndent(Nothing)) + End Sub + Public Sub TestParameter1() @@ -3007,12 +3015,12 @@ end class" Dim point = projectedDocument.GetTextView().BufferGraph.MapDownToBuffer(indentationLine.Start, PointTrackingMode.Negative, subjectDocument.GetTextBuffer(), PositionAffinity.Predecessor) TestIndentation( - point.Value, expectedIndentation, projectedDocument.GetTextView(), subjectDocument, workspace.GlobalOptions) + point.Value, expectedIndentation, projectedDocument.GetTextView(), subjectDocument) End Using End Sub ''' 0-based. The line number in code to get indentation for. - Private Sub AssertSmartIndent( + Private Shared Sub AssertSmartIndent( code As String, indentationLine As Integer, expectedIndentation As Integer?, Optional indentStyle As FormattingOptions.IndentStyle = FormattingOptions.IndentStyle.Smart) @@ -3021,13 +3029,17 @@ end class" End Sub ''' 0-based. The line number in code to get indentation for. - Private Sub AssertSmartIndent( + Private Shared Sub AssertSmartIndent( code As String, indentationLine As Integer, expectedIndentation As Integer?, useTabs As Boolean, indentStyle As FormattingOptions.IndentStyle) Using workspace = TestWorkspace.CreateVisualBasic(code) - TestIndentation(workspace, indentationLine, expectedIndentation, indentStyle, useTabs) + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ + .WithChangedOption(FormattingOptions.SmartIndent, LanguageNames.VisualBasic, indentStyle) _ + .WithChangedOption(FormattingOptions.UseTabs, LanguageNames.VisualBasic, useTabs))) + + TestIndentation(workspace, indentationLine, expectedIndentation) End Using End Sub End Class diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs index 6c87012ea5d75..59f1d7906edb5 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs @@ -144,7 +144,7 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, // Set the caret position to the properly indented column in the desired line. var newDocument = document.WithText(formattedText); var newDocumentText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); - var caretPosition = GetIndentedLinePosition(newDocument, newDocumentText, desiredCaretLine.LineNumber, options, cancellationToken); + var caretPosition = GetIndentedLinePosition(newDocument, newDocumentText, desiredCaretLine.LineNumber, cancellationToken); // The new line edit is calculated against the original text, d0, to get text d1. // The formatting edits are calculated against d1 to get text d2. @@ -158,10 +158,10 @@ static TextLine GetLineBetweenCurlys(int closingPosition, SourceText text) return text.Lines[closingBraceLineNumber - 1]; } - static LinePosition GetIndentedLinePosition(Document document, SourceText sourceText, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) + static LinePosition GetIndentedLinePosition(Document document, SourceText sourceText, int lineNumber, CancellationToken cancellationToken) { var indentationService = document.GetRequiredLanguageService(); - var indentation = indentationService.GetIndentation(document, lineNumber, options, cancellationToken); + var indentation = indentationService.GetIndentation(document, lineNumber, cancellationToken); var baseLinePosition = sourceText.Lines.GetLinePosition(indentation.BasePosition); var offsetOfBacePosition = baseLinePosition.Character; diff --git a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs index ac4cbcdc24c4b..23f3c9dd11369 100644 --- a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -63,8 +62,7 @@ protected override async Task FixAllAsync( var diagnostic = diagnostics.First(); var namespaceDecl = (BaseNamespaceDeclarationSyntax)diagnostic.AdditionalLocations[0].FindNode(cancellationToken); - var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var converted = await ConvertAsync(document, namespaceDecl, options, cancellationToken).ConfigureAwait(false); + var converted = await ConvertAsync(document, namespaceDecl, cancellationToken).ConfigureAwait(false); editor.ReplaceNode( editor.OriginalRoot, diff --git a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs index 1d305b357a6f6..d6a30423155f0 100644 --- a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -53,10 +52,8 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (info == null) return; - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - context.RegisterRefactoring(new MyCodeAction( - info.Value.title, c => ConvertAsync(document, namespaceDecl, formattingOptions, c), info.Value.equivalenceKey)); + info.Value.title, c => ConvertAsync(document, namespaceDecl, c), info.Value.equivalenceKey)); } private static bool IsValidPosition(BaseNamespaceDeclarationSyntax baseDeclaration, int position) diff --git a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceTransform.cs b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceTransform.cs index b4d770f28cb3c..f46abe8ab84ad 100644 --- a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceTransform.cs +++ b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceTransform.cs @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ConvertNamespace { internal static class ConvertNamespaceTransform { - public static async Task ConvertAsync(Document document, BaseNamespaceDeclarationSyntax baseNamespace, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public static async Task ConvertAsync(Document document, BaseNamespaceDeclarationSyntax baseNamespace, CancellationToken cancellationToken) { switch (baseNamespace) { @@ -39,7 +39,7 @@ public static async Task ConvertAsync(Document document, BaseNamespace return await ConvertFileScopedNamespaceAsync(document, fileScopedNamespace, cancellationToken).ConfigureAwait(false); case NamespaceDeclarationSyntax namespaceDeclaration: - var (doc, _) = await ConvertNamespaceDeclarationAsync(document, namespaceDeclaration, options, cancellationToken).ConfigureAwait(false); + var (doc, _) = await ConvertNamespaceDeclarationAsync(document, namespaceDeclaration, cancellationToken).ConfigureAwait(false); return doc; default: @@ -47,13 +47,12 @@ public static async Task ConvertAsync(Document document, BaseNamespace } } - public static async Task<(Document document, TextSpan semicolonSpan)> ConvertNamespaceDeclarationAsync(Document document, NamespaceDeclarationSyntax namespaceDeclaration, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public static async Task<(Document document, TextSpan semicolonSpan)> ConvertNamespaceDeclarationAsync(Document document, NamespaceDeclarationSyntax namespaceDeclaration, CancellationToken cancellationToken) { // First, determine how much indentation we had inside the original block namespace. We'll attempt to remove // that much indentation from each applicable line after we conver the block namespace to a file scoped // namespace. - - var indentation = await GetIndentationAsync(document, namespaceDeclaration, options, cancellationToken).ConfigureAwait(false); + var indentation = await GetIndentationAsync(document, namespaceDeclaration, cancellationToken).ConfigureAwait(false); // Next, actually replace the block namespace with the file scoped namespace. var annotation = new SyntaxAnnotation(); @@ -78,7 +77,7 @@ public static async Task ConvertAsync(Document document, BaseNamespace return (document.WithSyntaxRoot(updatedRoot), fileScopedNamespace.SemicolonToken.Span); } - private static async Task GetIndentationAsync(Document document, NamespaceDeclarationSyntax namespaceDeclaration, SyntaxFormattingOptions options, CancellationToken cancellationToken) + private static async Task GetIndentationAsync(Document document, NamespaceDeclarationSyntax namespaceDeclaration, CancellationToken cancellationToken) { var indentationService = document.GetRequiredLanguageService(); var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); @@ -88,12 +87,15 @@ public static async Task ConvertAsync(Document document, BaseNamespace if (openBraceLine == closeBraceLine) return null; - // Auto-formatting options are not relevant since they only control behavior on typing. - var indentationOptions = new IndentationOptions(options, AutoFormattingOptions.Default); + var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var style = options.GetOption(FormattingOptions.SmartIndent, document.Project.Language); + + var indentation = indentationService.GetIndentation(document, openBraceLine + 1, style, cancellationToken); - var indentation = indentationService.GetIndentation(document, openBraceLine + 1, indentationOptions, cancellationToken); + var useTabs = options.GetOption(FormattingOptions.UseTabs); + var tabSize = options.GetOption(FormattingOptions.TabSize); - return indentation.GetIndentationString(sourceText, options.UseTabs, options.TabSize); + return indentation.GetIndentationString(sourceText, useTabs, tabSize); } private static async Task<(Document document, TextSpan semicolonSpan)> DedentNamespaceAsync( diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs index a1848a77a25ff..f65ebc0594a6d 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs @@ -71,14 +71,12 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var canBeSingleLine = CanBeSingleLine(characters); - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - if (canBeSingleLine) { context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_raw_string, - c => UpdateDocumentAsync(document, span, ConvertToRawKind.SingleLine, formattingOptions, c), + c => UpdateDocumentAsync(document, span, ConvertToRawKind.SingleLine, c), nameof(CSharpFeaturesResources.Convert_to_raw_string) + "-" + ConvertToRawKind.SingleLine, priority), token.Span); @@ -91,7 +89,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_raw_string, - c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLineIndented, formattingOptions, c), + c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLineIndented, c), nameof(CSharpFeaturesResources.Convert_to_raw_string), priority), token.Span); @@ -101,7 +99,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_raw_string_no_indent, - c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLine, formattingOptions, c), + c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLine, c), nameof(CSharpFeaturesResources.Convert_to_raw_string_no_indent), priority), token.Span); @@ -110,14 +108,17 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } private static async Task UpdateDocumentAsync( - Document document, TextSpan span, ConvertToRawKind kind, SyntaxFormattingOptions options, CancellationToken cancellationToken) + Document document, TextSpan span, ConvertToRawKind kind, CancellationToken cancellationToken) { + var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var newLine = options.GetOption(FormattingOptions.NewLine); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(span.Start); Contract.ThrowIfFalse(span.IntersectsWith(token.Span)); Contract.ThrowIfFalse(token.Kind() == SyntaxKind.StringLiteralToken); - var replacement = GetReplacementToken(document, token, kind, options, cancellationToken); + var replacement = GetReplacementToken(document, token, kind, newLine, cancellationToken); return document.WithSyntaxRoot(root.ReplaceToken(token, replacement)); } @@ -125,19 +126,19 @@ private static SyntaxToken GetReplacementToken( Document document, SyntaxToken token, ConvertToRawKind kind, - SyntaxFormattingOptions options, + string newLine, CancellationToken cancellationToken) { return kind switch { ConvertToRawKind.SingleLine => ConvertToSingleLineRawString(token), - ConvertToRawKind.MultiLine => ConvertToMultiLineRawString(token, options.NewLine), - ConvertToRawKind.MultiLineIndented => ConvertToMultiLineRawIndentedString(document, token, options, cancellationToken), + ConvertToRawKind.MultiLine => ConvertToMultiLineRawString(token, newLine), + ConvertToRawKind.MultiLineIndented => ConvertToMultiLineRawIndentedString(document, token, newLine, cancellationToken), _ => throw ExceptionUtilities.UnexpectedValue(kind), }; } - private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document, SyntaxToken token, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document, SyntaxToken token, string newLine, CancellationToken cancellationToken) { var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); @@ -145,15 +146,12 @@ private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document // Have to make sure we have a delimiter longer than any quote sequence in the string. var longestQuoteSequence = GetLongestQuoteSequence(characters); var quoteDelimeterCount = Math.Max(3, longestQuoteSequence + 1); - - // Auto-formatting options are not relevant since they only control behavior on typing. - var indentationOptions = new IndentationOptions(formattingOptions, AutoFormattingOptions.Default); - var indentation = token.GetPreferredIndentation(document, indentationOptions, cancellationToken); + var indentation = token.GetPreferredIndentation(document, cancellationToken); using var _ = PooledStringBuilder.GetInstance(out var builder); builder.Append('"', quoteDelimeterCount); - builder.Append(formattingOptions.NewLine); + builder.Append(newLine); var atStartOfLine = true; for (int i = 0, n = characters.Length; i < n; i++) @@ -175,7 +173,7 @@ private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document ch.AppendTo(builder); } - builder.Append(formattingOptions.NewLine); + builder.Append(newLine); builder.Append(indentation); builder.Append('"', quoteDelimeterCount); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs index ba53dbbc9a20f..c0256ecb8e2c2 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs @@ -26,7 +26,7 @@ public CSharpAccessibilityModifiersNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken) { var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var accessibilityPreferences = documentOptions.GetOption(CodeStyleOptions2.RequireAccessibilityModifiers, document.Project.Language); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs b/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs index 026fee4708a1d..5f292e5ad6d07 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs @@ -91,21 +91,27 @@ public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormatting public async Task> GetFormattingChangesAsync( Document document, TextSpan? textSpan, - SyntaxFormattingOptions options, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var span = textSpan ?? new TextSpan(0, root.FullSpan.Length); var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span); + if (documentOptions == null) + { + var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: true, cancellationToken: cancellationToken).ConfigureAwait(false); + } var services = document.Project.Solution.Workspace.Services; - return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, options, cancellationToken).ToImmutableArray(); + var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, services, document.Project.Language); + return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, cancellationToken).ToImmutableArray(); } public async Task> GetFormattingChangesOnPasteAsync( Document document, TextSpan textSpan, - SyntaxFormattingOptions options, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -116,7 +122,14 @@ public async Task> GetFormattingChangesOnPasteAsync( var rules = new List() { new PasteFormattingRule() }; rules.AddRange(service.GetDefaultFormattingRules()); - var result = service.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(formattingSpan), options, rules, cancellationToken); + if (documentOptions == null) + { + var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); + var result = service.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(formattingSpan), formattingOptions, rules, cancellationToken); return result.GetTextChanges(cancellationToken).ToImmutableArray(); } @@ -128,7 +141,7 @@ private static IEnumerable GetFormattingRules(Document d } Task> IFormattingInteractionService.GetFormattingChangesOnReturnAsync( - Document document, int caretPosition, CancellationToken cancellationToken) + Document document, int caretPosition, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) => SpecializedTasks.EmptyImmutableArray(); private static async Task TokenShouldNotFormatOnTypeCharAsync( @@ -168,7 +181,7 @@ public async Task> GetFormattingChangesAsync( Document document, char typedChar, int caretPosition, - IndentationOptions options, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { // first, find the token user just typed. @@ -195,6 +208,16 @@ public async Task> GetFormattingChangesAsync( return ImmutableArray.Empty; } + var services = document.Project.Solution.Workspace.Services; + + if (documentOptions == null) + { + var inferredIndentationService = services.GetRequiredService(); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + var options = IndentationOptions.From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); + // Do not attempt to format on open/close brace if autoformat on close brace feature is // off, instead just smart indent. // diff --git a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs index 050e3b16ed36a..d2d8d33740221 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpNamespaceDeclarationNewDocumentFormattingProvider.cs @@ -27,7 +27,7 @@ public CSharpNamespaceDeclarationNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken) { var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = (CompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -36,7 +36,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? if (namespaces.Count != 1) return document; - return await ConvertNamespaceTransform.ConvertAsync(document, namespaces[0], options, cancellationToken).ConfigureAwait(false); + return await ConvertNamespaceTransform.ConvertAsync(document, namespaces[0], cancellationToken).ConfigureAwait(false); } private static IEnumerable GetNamespacesToReplace(Document document, CompilationUnitSyntax root, DocumentOptionSet optionSet) diff --git a/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs index ed370a01dd77a..eb8d0f0291811 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpOrganizeUsingsNewDocumentFormattingProvider.cs @@ -21,7 +21,7 @@ public CSharpOrganizeUsingsNewDocumentFormattingProvider() { } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken) { var organizedDocument = await Formatter.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false); return await MisplacedUsingDirectivesCodeFixProvider.TransformDocumentIfRequiredAsync(organizedDocument, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs index c6e2382ac162a..af391391ad71f 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs @@ -9,7 +9,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.SplitStringLiteral @@ -26,11 +25,11 @@ public InterpolatedStringSplitter( SyntaxNode root, SourceText sourceText, InterpolatedStringExpressionSyntax interpolatedStringExpression, - IndentationOptions options, bool useTabs, int tabSize, + FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) - : base(document, position, root, sourceText, options, useTabs, tabSize, cancellationToken) + : base(document, position, root, sourceText, useTabs, tabSize, indentStyle, cancellationToken) { _interpolatedStringExpression = interpolatedStringExpression; } diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs index 5ed690b31fe9c..4d66f047857a8 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/SimpleStringSplitter.cs @@ -7,7 +7,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.SplitStringLiteral @@ -22,8 +21,8 @@ private sealed class SimpleStringSplitter : StringSplitter public SimpleStringSplitter( Document document, int position, SyntaxNode root, SourceText sourceText, SyntaxToken token, - in IndentationOptions options, bool useTabs, int tabSize, CancellationToken cancellationToken) - : base(document, position, root, sourceText, options, useTabs, tabSize, cancellationToken) + bool useTabs, int tabSize, FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) + : base(document, position, root, sourceText, useTabs, tabSize, indentStyle, cancellationToken) { _token = token; } diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs index 9062054e2faa0..0592a8a440474 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/StringSplitter.cs @@ -27,15 +27,17 @@ internal abstract partial class StringSplitter protected readonly int CursorPosition; protected readonly SourceText SourceText; protected readonly SyntaxNode Root; - protected readonly IndentationOptions Options; protected readonly int TabSize; protected readonly bool UseTabs; protected readonly CancellationToken CancellationToken; + private readonly FormattingOptions.IndentStyle _indentStyle; + public StringSplitter( Document document, int position, SyntaxNode root, SourceText sourceText, - in IndentationOptions options, bool useTabs, int tabSize, + bool useTabs, int tabSize, + FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) { Document = document; @@ -44,13 +46,13 @@ public StringSplitter( SourceText = sourceText; UseTabs = useTabs; TabSize = tabSize; - Options = options; + _indentStyle = indentStyle; CancellationToken = cancellationToken; } public static StringSplitter TryCreate( Document document, int position, - in IndentationOptions options, bool useTabs, int tabSize, + bool useTabs, int tabSize, FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) { var root = document.GetSyntaxRootSynchronously(cancellationToken); @@ -62,8 +64,8 @@ public static StringSplitter TryCreate( { return new SimpleStringSplitter( document, position, root, - sourceText, token, options, useTabs, tabSize, - cancellationToken); + sourceText, token, useTabs, tabSize, + indentStyle, cancellationToken); } var interpolatedStringExpression = TryGetInterpolatedStringExpression(token, position); @@ -72,7 +74,7 @@ public static StringSplitter TryCreate( return new InterpolatedStringSplitter( document, position, root, sourceText, interpolatedStringExpression, - options, useTabs, tabSize, cancellationToken); + useTabs, tabSize, indentStyle, cancellationToken); } return null; @@ -152,7 +154,7 @@ private string GetIndentString(SyntaxNode newRoot) var originalLineNumber = SourceText.Lines.GetLineFromPosition(CursorPosition).LineNumber; var desiredIndentation = indentationService.GetIndentation( - newDocument, originalLineNumber + 1, Options, CancellationToken); + newDocument, originalLineNumber + 1, _indentStyle, CancellationToken); var newSourceText = newDocument.GetSyntaxRootSynchronously(CancellationToken).SyntaxTree.GetText(CancellationToken); var baseLine = newSourceText.Lines.GetLineFromPosition(desiredIndentation.BasePosition); diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs index 5717a334ffa98..467df8966f241 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpSyntaxWrappingOptions.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Wrapping; namespace Microsoft.CodeAnalysis.CSharp.Wrapping @@ -15,18 +16,22 @@ internal sealed class CSharpSyntaxWrappingOptions : SyntaxWrappingOptions public readonly bool NewLinesForBracesInObjectCollectionArrayInitializers; public CSharpSyntaxWrappingOptions( - CSharpSyntaxFormattingOptions formattingOptions, + bool useTabs, + int tabSize, + string newLine, int wrappingColumn, OperatorPlacementWhenWrappingPreference operatorPlacement, bool newLinesForBracesInObjectCollectionArrayInitializers) - : base(formattingOptions, wrappingColumn, operatorPlacement) + : base(useTabs, tabSize, newLine, wrappingColumn, operatorPlacement) { NewLinesForBracesInObjectCollectionArrayInitializers = newLinesForBracesInObjectCollectionArrayInitializers; } public static CSharpSyntaxWrappingOptions Create(AnalyzerConfigOptions options, CodeActionOptions ideOptions) => new( - CSharpSyntaxFormattingOptions.Create(options), + useTabs: options.GetOption(FormattingOptions2.UseTabs), + tabSize: options.GetOption(FormattingOptions2.TabSize), + newLine: options.GetOption(FormattingOptions2.NewLine), operatorPlacement: options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), wrappingColumn: ideOptions.WrappingColumn, newLinesForBracesInObjectCollectionArrayInitializers: options.GetOption(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers)); diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs index 0e723e3457129..3051a24034ddf 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerNewDocumentFormattingProvider.cs @@ -19,7 +19,7 @@ internal abstract class AbstractAddFileBannerNewDocumentFormattingProvider : INe protected abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; } protected abstract AbstractFileHeaderHelper FileHeaderHelper { get; } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken) { var rootToFormat = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); @@ -28,7 +28,8 @@ public async Task FormatNewDocumentAsync(Document document, Document? var fileHeaderTemplate = documentOptions.GetOption(CodeStyleOptions2.FileHeaderTemplate); if (!string.IsNullOrEmpty(fileHeaderTemplate)) { - var newLineTrivia = SyntaxGeneratorInternal.EndOfLine(options.NewLine); + var newLineText = documentOptions.GetOption(FormattingOptions.NewLine, rootToFormat.Language); + var newLineTrivia = SyntaxGeneratorInternal.EndOfLine(newLineText); var rootWithFileHeader = await AbstractFileHeaderCodeFixProvider.GetTransformedSyntaxRootAsync( SyntaxGenerator.SyntaxFacts, FileHeaderHelper, diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentOptions.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentOptions.cs index e29ba4043d6f9..3612d368496da 100644 --- a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentOptions.cs +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentOptions.cs @@ -2,13 +2,43 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Runtime.Serialization; +using System; +using System.Collections.Immutable; +using System.Composition; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Options.Providers; -namespace Microsoft.CodeAnalysis.DocumentationComments; +namespace Microsoft.CodeAnalysis.DocumentationComments +{ + internal readonly record struct DocumentationCommentOptions( + bool AutoXmlDocCommentGeneration, + int TabSize, + bool UseTabs, + string NewLine) + { + [ExportSolutionOptionProvider, Shared] + internal sealed class Metadata : IOptionProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public Metadata() + { + } -[DataContract] -internal readonly record struct DocumentationCommentOptions( - [property: DataMember(Order = 0)] bool AutoXmlDocCommentGeneration, - [property: DataMember(Order = 1)] int TabSize, - [property: DataMember(Order = 2)] bool UseTabs, - [property: DataMember(Order = 3)] string NewLine); + public ImmutableArray Options { get; } = ImmutableArray.Create( + AutoXmlDocCommentGeneration); + + public static readonly PerLanguageOption2 AutoXmlDocCommentGeneration = new(nameof(DocumentationCommentOptions), nameof(AutoXmlDocCommentGeneration), defaultValue: true, + storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.AutoComment" : "TextEditor.%LANGUAGE%.Specific.Automatic XML Doc Comment Generation")); + } + + public static DocumentationCommentOptions From(DocumentOptionSet options) + => new( + AutoXmlDocCommentGeneration: options.GetOption(Metadata.AutoXmlDocCommentGeneration), + TabSize: options.GetOption(FormattingOptions.TabSize), + UseTabs: options.GetOption(FormattingOptions.UseTabs), + NewLine: options.GetOption(FormattingOptions.NewLine)); + } +} diff --git a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs index e7f59e6c693dc..8be7bfe176e3e 100644 --- a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs +++ b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs @@ -32,7 +32,7 @@ private IEnumerable GetProviders() return _providerValues; } - public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public async Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken) { foreach (var provider in GetProviders()) { @@ -46,7 +46,7 @@ public async Task FormatNewDocumentAsync(Document document, Document? // First we ask the provider to "format" the document. This could be formatting in terms // of adjusting block scopes to file scopes etc., but it could also be more akin to fixers // like adding access modifiers, or adding .ConfigureAwait() calls etc. - document = await provider.FormatNewDocumentAsync(document, hintDocument, options, cancellationToken).ConfigureAwait(false); + document = await provider.FormatNewDocumentAsync(document, hintDocument, cancellationToken).ConfigureAwait(false); // Now that the above has changed the document, we use the code action engine to clean up the document // before we call the next provider, otherwise they might not see things as they are meant to be. diff --git a/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs b/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs index 685e79d7d7ac6..84296fa0cb7c2 100644 --- a/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs +++ b/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; @@ -26,26 +25,26 @@ internal interface IFormattingInteractionService : ILanguageService bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch); /// - /// Returns the text changes necessary to format the document. If is provided, + /// Returns the text changes necessary to format the document. If "textSpan" is provided, /// only the text changes necessary to format that span are needed. /// - Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken); + Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken); /// /// Returns the text changes necessary to format the document on paste operation. /// - Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken); + Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken); /// /// Returns the text changes necessary to format the document after the user enters a /// character. The position provided is the position of the caret in the document after /// the character been inserted into the document. /// - Task> GetFormattingChangesAsync(Document document, char typedChar, int position, IndentationOptions options, CancellationToken cancellationToken); + Task> GetFormattingChangesAsync(Document document, char typedChar, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken); /// /// Returns the text changes necessary to format the document after the user enters a Return /// The position provided is the position of the caret in the document after Return. - Task> GetFormattingChangesOnReturnAsync(Document document, int position, CancellationToken cancellationToken); + Task> GetFormattingChangesOnReturnAsync(Document document, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs b/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs index 3012091569619..c75a47fb9e328 100644 --- a/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs +++ b/src/Features/Core/Portable/Formatting/INewDocumentFormattingProvider.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Formatting { internal interface INewDocumentFormattingProvider { - /// - Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken); + /// + Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs b/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs index 74b3452f825f7..e22870c4e27f8 100644 --- a/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs +++ b/src/Features/Core/Portable/Formatting/INewDocumentFormattingService.cs @@ -16,6 +16,6 @@ internal interface INewDocumentFormattingService : ILanguageService /// The document to format. /// An optional additional document that can be used to inform the formatting operation. /// A cancellation token. - Task FormatNewDocumentAsync(Document document, Document? hintDocument, SyntaxFormattingOptions options, CancellationToken cancellationToken); + Task FormatNewDocumentAsync(Document document, Document? hintDocument, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 4daf9502e6281..0a34d81af7323 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -312,8 +312,7 @@ private async Task> GetGenerateInNewFileOperati var formattingService = newDocument.GetLanguageService(); if (formattingService is not null) { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(_semanticDocument.Document, _cancellationToken).ConfigureAwait(false); - codeGenResult = await formattingService.FormatNewDocumentAsync(codeGenResult, _semanticDocument.Document, formattingOptions, _cancellationToken).ConfigureAwait(false); + codeGenResult = await formattingService.FormatNewDocumentAsync(codeGenResult, _semanticDocument.Document, _cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs b/src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs deleted file mode 100644 index 1386ea45a8783..0000000000000 --- a/src/Features/Core/Portable/Options/AutoFormattingOptionsStorage.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.Formatting; - -// TODO: move to LSP layer - -internal static class AutoFormattingOptionsStorage -{ - public static AutoFormattingOptions GetAutoFormattingOptions(this IGlobalOptionService globalOptions, string language) - => new( - IndentStyle: globalOptions.GetOption(SmartIndent, language), - FormatOnReturn: globalOptions.GetOption(FormatOnReturn, language), - FormatOnTyping: globalOptions.GetOption(FormatOnTyping, language), - FormatOnSemicolon: globalOptions.GetOption(FormatOnSemicolon, language), - FormatOnCloseBrace: globalOptions.GetOption(FormatOnCloseBrace, language)); - - internal static PerLanguageOption2 SmartIndent => FormattingOptions.SmartIndent2; - - internal static readonly PerLanguageOption2 FormatOnReturn = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnReturn", AutoFormattingOptions.Default.FormatOnReturn, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Return")); - - public static readonly PerLanguageOption2 FormatOnTyping = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnTyping", AutoFormattingOptions.Default.FormatOnTyping, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Typing")); - - public static readonly PerLanguageOption2 FormatOnSemicolon = new( - "FormattingOptions", OptionGroup.Default, "AutoFormattingOnSemicolon", AutoFormattingOptions.Default.FormatOnSemicolon, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Semicolon")); - - public static readonly PerLanguageOption2 FormatOnCloseBrace = new( - "BraceCompletionOptions", "AutoFormattingOnCloseBrace", defaultValue: AutoFormattingOptions.Default.FormatOnCloseBrace, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Close Brace")); -} diff --git a/src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs b/src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs deleted file mode 100644 index 249bb5c4c3a24..0000000000000 --- a/src/Features/Core/Portable/Options/DocumentationCommentOptionsStorage.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.DocumentationComments; - -// TODO: move to LSP layer - -internal static class DocumentationCommentOptionsStorage -{ - public static DocumentationCommentOptions GetDocumentationCommentOptions(this IGlobalOptionService globalOptions, DocumentOptionSet documentOptions) - => new( - AutoXmlDocCommentGeneration: globalOptions.GetOption(AutoXmlDocCommentGeneration, documentOptions.Language), - TabSize: documentOptions.GetOption(FormattingOptions.TabSize), - UseTabs: documentOptions.GetOption(FormattingOptions.UseTabs), - NewLine: documentOptions.GetOption(FormattingOptions.NewLine)); - - public static DocumentationCommentOptions GetDocumentationCommentOptions(this IGlobalOptionService globalOptions, SyntaxFormattingOptions formattingOptions, string language) - => new( - AutoXmlDocCommentGeneration: globalOptions.GetOption(AutoXmlDocCommentGeneration, language), - TabSize: formattingOptions.TabSize, - UseTabs: formattingOptions.UseTabs, - NewLine: formattingOptions.NewLine); - - public static readonly PerLanguageOption2 AutoXmlDocCommentGeneration = new( - "DocumentationCommentOptions", "AutoXmlDocCommentGeneration", defaultValue: true, - storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.AutoComment" : "TextEditor.%LANGUAGE%.Specific.Automatic XML Doc Comment Generation")); - -} diff --git a/src/Features/Core/Portable/Options/IndentationOptionsStorage.cs b/src/Features/Core/Portable/Options/IndentationOptionsStorage.cs deleted file mode 100644 index 44df45a4dccd0..0000000000000 --- a/src/Features/Core/Portable/Options/IndentationOptionsStorage.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.Indentation; - -internal static class IndentationOptionsStorage -{ - // TODO: move to LSP layer - public static async Task GetIndentationOptionsAsync(this IGlobalOptionService globalOptions, Document document, CancellationToken cancellationToken) - { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var autoFormattingOptions = globalOptions.GetAutoFormattingOptions(document.Project.Language); - return new(formattingOptions, autoFormattingOptions); - } -} diff --git a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs index 09cb120ce4fe4..c075b5a90e15c 100644 --- a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs +++ b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs @@ -87,11 +87,10 @@ internal static class ExtractTypeHelpers context, cancellationToken).ConfigureAwait(false); - var formattingService = newTypeDocument.GetLanguageService(); - if (formattingService is not null) + var formattingSerivce = newTypeDocument.GetLanguageService(); + if (formattingSerivce is not null) { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(newTypeDocument, cancellationToken).ConfigureAwait(false); - newTypeDocument = await formattingService.FormatNewDocumentAsync(newTypeDocument, hintDocument, formattingOptions, cancellationToken).ConfigureAwait(false); + newTypeDocument = await formattingSerivce.FormatNewDocumentAsync(newTypeDocument, hintDocument, cancellationToken).ConfigureAwait(false); } var syntaxRoot = await newTypeDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs index 65a568a47b31a..09f3e7c4a5fe3 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractCodeActionComputer.cs @@ -4,7 +4,6 @@ #nullable disable -using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -78,7 +77,7 @@ public AbstractCodeActionComputer( var generator = SyntaxGenerator.GetGenerator(document); var generatorInternal = document.GetRequiredLanguageService(); - NewLineTrivia = new SyntaxTriviaList(generatorInternal.EndOfLine(options.FormattingOptions.NewLine)); + NewLineTrivia = new SyntaxTriviaList(generatorInternal.EndOfLine(options.NewLine)); SingleWhitespaceTrivia = new SyntaxTriviaList(generator.Whitespace(" ")); } @@ -89,26 +88,19 @@ protected string GetSmartIndentationAfter(SyntaxNodeOrToken nodeOrToken) protected string GetIndentationAfter(SyntaxNodeOrToken nodeOrToken, FormattingOptions.IndentStyle indentStyle) { - var newLine = Options.FormattingOptions.NewLine; - var newSourceText = OriginalSourceText.WithChanges(new TextChange(new TextSpan(nodeOrToken.Span.End, 0), newLine)); + var newSourceText = OriginalSourceText.WithChanges(new TextChange(new TextSpan(nodeOrToken.Span.End, 0), Options.NewLine)); newSourceText = newSourceText.WithChanges( - new TextChange(TextSpan.FromBounds(nodeOrToken.Span.End + newLine.Length, newSourceText.Length), "")); + new TextChange(TextSpan.FromBounds(nodeOrToken.Span.End + Options.NewLine.Length, newSourceText.Length), "")); var newDocument = OriginalDocument.WithText(newSourceText); - // The only auto-formatting option that's relevant is indent style. Others only control behavior on typing. - var indentationOptions = new IndentationOptions( - Options.FormattingOptions, - new AutoFormattingOptions( - IndentStyle: indentStyle)); - var indentationService = Wrapper.IndentationService; var originalLineNumber = newSourceText.Lines.GetLineFromPosition(nodeOrToken.Span.End).LineNumber; var desiredIndentation = indentationService.GetIndentation( newDocument, originalLineNumber + 1, - indentationOptions, + indentStyle, CancellationToken); - return desiredIndentation.GetIndentationString(newSourceText, Options.FormattingOptions.UseTabs, Options.FormattingOptions.TabSize); + return desiredIndentation.GetIndentationString(newSourceText, Options.UseTabs, Options.TabSize); } /// diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index e252c490e5dd1..00498c2fa0bcd 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Wrapping diff --git a/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs index 3f93d916b82b7..ed160c6a93512 100644 --- a/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -62,7 +61,7 @@ public BinaryExpressionCodeActionComputer( _indentAndAlignTrivia = new SyntaxTriviaList(generator.Whitespace( OriginalSourceText.GetOffset(binaryExpression.Span.Start) - .CreateIndentationString(options.FormattingOptions.UseTabs, options.FormattingOptions.TabSize))); + .CreateIndentationString(options.UseTabs, options.TabSize))); _smartIndentTrivia = new SyntaxTriviaList(generator.Whitespace( GetSmartIndentationAfter(_exprsAndOperators[1]))); diff --git a/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs b/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs index cd346692eedd7..1305d5462075a 100644 --- a/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/ChainedExpression/AbstractChainedExpressionWrapper.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; diff --git a/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs index ff7448f389004..de9f4dfbf9433 100644 --- a/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -85,7 +84,7 @@ public CallExpressionCodeActionComputer( var firstPeriod = chunks[0][0]; _firstPeriodIndentationTrivia = new SyntaxTriviaList(generator.Whitespace( - OriginalSourceText.GetOffset(firstPeriod.SpanStart).CreateIndentationString(options.FormattingOptions.UseTabs, options.FormattingOptions.TabSize))); + OriginalSourceText.GetOffset(firstPeriod.SpanStart).CreateIndentationString(options.UseTabs, options.TabSize))); _smartIndentTrivia = new SyntaxTriviaList(generator.Whitespace( GetSmartIndentationAfter(firstPeriod))); diff --git a/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs b/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs index fe9eeb2513788..95f1879510e79 100644 --- a/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs +++ b/src/Features/Core/Portable/Wrapping/ISyntaxWrapper.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Indentation; namespace Microsoft.CodeAnalysis.Wrapping { diff --git a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs index 6415516633812..25bd17606fe15 100644 --- a/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/SeparatedSyntaxList/SeparatedSyntaxListCodeActionComputer.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -108,7 +107,7 @@ private string GetAfterOpenTokenIdentation() var openToken = _listSyntax.GetFirstToken(); var afterOpenTokenOffset = OriginalSourceText.GetOffset(openToken.Span.End); - var indentString = afterOpenTokenOffset.CreateIndentationString(Options.FormattingOptions.UseTabs, Options.FormattingOptions.TabSize); + var indentString = afterOpenTokenOffset.CreateIndentationString(Options.UseTabs, Options.TabSize); return indentString; } @@ -134,7 +133,7 @@ private string GetBraceTokenIndentation() var previousToken = _listSyntax.GetFirstToken().GetPreviousToken(); // Block indentation is the only style that correctly indents across all initializer expressions - return GetIndentationAfter(previousToken, FormattingOptions.IndentStyle.Block); + return GetIndentationAfter(previousToken, Formatting.FormattingOptions.IndentStyle.Block); } protected override async Task> ComputeWrappingGroupsAsync() diff --git a/src/Features/Core/Portable/Wrapping/SyntaxWrappingOptions.cs b/src/Features/Core/Portable/Wrapping/SyntaxWrappingOptions.cs index 2b00e46f68970..a7a2883923fd4 100644 --- a/src/Features/Core/Portable/Wrapping/SyntaxWrappingOptions.cs +++ b/src/Features/Core/Portable/Wrapping/SyntaxWrappingOptions.cs @@ -2,23 +2,31 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.Wrapping { internal abstract class SyntaxWrappingOptions { - public readonly SyntaxFormattingOptions FormattingOptions; + public readonly bool UseTabs; + public readonly int TabSize; + public readonly string NewLine; public readonly int WrappingColumn; public readonly OperatorPlacementWhenWrappingPreference OperatorPlacement; protected SyntaxWrappingOptions( - SyntaxFormattingOptions formattingOptions, + bool useTabs, + int tabSize, + string newLine, int wrappingColumn, OperatorPlacementWhenWrappingPreference operatorPlacement) { - FormattingOptions = formattingOptions; + UseTabs = useTabs; + TabSize = tabSize; + NewLine = newLine; WrappingColumn = wrappingColumn; OperatorPlacement = operatorPlacement; } diff --git a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 4d6181585f501..4b8bb4e256a50 100644 --- a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -11,9 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentHighlighting; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.NavigateTo; @@ -659,24 +657,24 @@ public static ProjectId ProjectContextToProjectId(LSP.VSProjectContext projectCo debugName: projectContext.Id.Substring(delimiter + 1)); } - public static async Task GetFormattingOptionsAsync( + public static async Task FormattingOptionsToDocumentOptionsAsync( LSP.FormattingOptions? options, Document document, CancellationToken cancellationToken) { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); if (options != null) { // LSP doesn't currently support indent size as an option. However, except in special // circumstances, indent size is usually equivalent to tab size, so we'll just set it. - formattingOptions = formattingOptions.With( - useTabs: !options.InsertSpaces, - tabSize: options.TabSize, - indentationSize: options.TabSize); + documentOptions = documentOptions + .WithChangedOption(Formatting.FormattingOptions.UseTabs, !options.InsertSpaces) + .WithChangedOption(Formatting.FormattingOptions.TabSize, options.TabSize) + .WithChangedOption(Formatting.FormattingOptions.IndentationSize, options.TabSize); } - return formattingOptions; + return documentOptions; } public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray tags, Document document, bool featureSupportsMarkdown) diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index 602e0e05bd027..5e5717f3d7de5 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -21,7 +20,7 @@ internal abstract class AbstractFormatDocumentHandlerBase false; public override bool RequiresLSPSolution => true; - protected static async Task GetTextEditsAsync( + protected async Task GetTextEditsAsync( RequestContext context, LSP.FormattingOptions options, CancellationToken cancellationToken, @@ -42,12 +41,21 @@ internal abstract class AbstractFormatDocumentHandlerBase ProtocolConversions.TextChangeToTextEdit(change, text))); return edits.ToArrayAndFree(); } + + protected virtual Task> GetFormattingChangesAsync( + IFormattingInteractionService formattingService, + Document document, + TextSpan? textSpan, + DocumentOptionSet documentOptions, + CancellationToken cancellationToken) + => formattingService.GetFormattingChangesAsync(document, textSpan, documentOptions, cancellationToken); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs index e435b8ce46d8e..4c4d5f3f3bc40 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportRoslynLanguagesLspRequestHandlerProvider(typeof(FormatDocumentHandler)), Shared] [Method(LSP.Methods.TextDocumentFormattingName)] - internal sealed class FormatDocumentHandler : AbstractFormatDocumentHandlerBase + internal class FormatDocumentHandler : AbstractFormatDocumentHandlerBase { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index 88970caf249f1..003d8462a93d2 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -22,18 +21,15 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportRoslynLanguagesLspRequestHandlerProvider(typeof(FormatDocumentOnTypeHandler)), Shared] [Method(Methods.TextDocumentOnTypeFormattingName)] - internal sealed class FormatDocumentOnTypeHandler : AbstractStatelessRequestHandler + internal class FormatDocumentOnTypeHandler : AbstractStatelessRequestHandler { - private readonly IGlobalOptionService _globalOptions; - public override bool MutatesSolutionState => false; public override bool RequiresLSPSolution => true; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) + public FormatDocumentOnTypeHandler() { - _globalOptions = globalOptions; } public override TextDocumentIdentifier? GetTextDocumentIdentifier(DocumentOnTypeFormattingParams request) => request.TextDocument; @@ -57,20 +53,20 @@ public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) return edits.ToArrayAndFree(); } + // We should use the options passed in by LSP instead of the document's options. + var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync( + request.Options, document, cancellationToken).ConfigureAwait(false); + IList? textChanges; if (SyntaxFacts.IsNewLine(request.Character[0])) { - textChanges = await formattingService.GetFormattingChangesOnReturnAsync( - document, position, cancellationToken).ConfigureAwait(false); + textChanges = await GetFormattingChangesOnReturnAsync( + formattingService, document, position, documentOptions, cancellationToken).ConfigureAwait(false); } else { - // We should use the options passed in by LSP instead of the document's options. - var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, cancellationToken).ConfigureAwait(false); - var indentationOptions = new IndentationOptions(formattingOptions, _globalOptions.GetAutoFormattingOptions(document.Project.Language)); - - textChanges = await formattingService.GetFormattingChangesAsync( - document, request.Character[0], position, indentationOptions, cancellationToken).ConfigureAwait(false); + textChanges = await GetFormattingChangesAsync( + formattingService, document, request.Character[0], position, documentOptions, cancellationToken).ConfigureAwait(false); } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); @@ -81,5 +77,22 @@ public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) return edits.ToArrayAndFree(); } + + protected virtual async Task?> GetFormattingChangesOnReturnAsync( + IFormattingInteractionService formattingService, + Document document, + int position, + DocumentOptionSet documentOptions, + CancellationToken cancellationToken) + => await formattingService.GetFormattingChangesOnReturnAsync(document, position, documentOptions, cancellationToken).ConfigureAwait(false); + + protected virtual async Task?> GetFormattingChangesAsync( + IFormattingInteractionService formattingService, + Document document, + char typedChar, + int position, + DocumentOptionSet documentOptions, + CancellationToken cancellationToken) + => await formattingService.GetFormattingChangesAsync(document, typedChar, position, documentOptions, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs index 646b0c7f318a8..a83f246b48926 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportRoslynLanguagesLspRequestHandlerProvider(typeof(FormatDocumentRangeHandler)), Shared] [Method(Methods.TextDocumentRangeFormattingName)] - internal sealed class FormatDocumentRangeHandler : AbstractFormatDocumentHandlerBase + internal class FormatDocumentRangeHandler : AbstractFormatDocumentHandlerBase { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs index 99540d07f0711..1b6234e8997fc 100644 --- a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; @@ -98,9 +97,10 @@ public InlineCompletionsHandler(XmlSnippetParser xmlSnippetParser) } // Use the formatting options specified by the client to format the snippet. - var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, context.Document, cancellationToken).ConfigureAwait(false); + var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync( + request.Options, context.Document, cancellationToken).ConfigureAwait(false); - var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, formattingOptions, cancellationToken).ConfigureAwait(false); + var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, documentOptions, cancellationToken).ConfigureAwait(false); return new VSInternalInlineCompletionList { @@ -122,7 +122,7 @@ public InlineCompletionsHandler(XmlSnippetParser xmlSnippetParser) /// /// Note that the operations in this method are sensitive to the context in the document and so must be calculated on each request. /// - private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet parsedSnippet, TextSpan snippetShortcut, Document originalDocument, SourceText originalSourceText, SyntaxFormattingOptions options, CancellationToken cancellationToken) + private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet parsedSnippet, TextSpan snippetShortcut, Document originalDocument, SourceText originalSourceText, DocumentOptionSet documentOptions, CancellationToken cancellationToken) { // Calculate the snippet text with defaults + snippet function results. var (snippetFullText, fields, caretSpan) = await GetReplacedSnippetTextAsync( @@ -136,7 +136,7 @@ private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet p var root = await originalDocument.WithText(documentWithSnippetText).GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var spanToFormat = TextSpan.FromBounds(textChange.Span.Start, snippetEndPosition); - var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace.Services, options, cancellationToken: cancellationToken) + var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace, options: documentOptions, cancellationToken: cancellationToken) ?.ToImmutableArray() ?? ImmutableArray.Empty; var formattedText = documentWithSnippetText.WithChanges(formattingChanges); diff --git a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs index 8e380c29cb8a6..3a9b8d4488c5a 100644 --- a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs @@ -26,11 +26,10 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportRoslynLanguagesLspRequestHandlerProvider(typeof(OnAutoInsertHandler)), Shared] [Method(LSP.VSInternalMethods.OnAutoInsertName)] - internal sealed class OnAutoInsertHandler : AbstractStatelessRequestHandler + internal class OnAutoInsertHandler : AbstractStatelessRequestHandler { private readonly ImmutableArray _csharpBraceCompletionServices; private readonly ImmutableArray _visualBasicBraceCompletionServices; - private readonly IGlobalOptionService _globalOptions; public override bool MutatesSolutionState => false; public override bool RequiresLSPSolution => true; @@ -39,12 +38,10 @@ internal sealed class OnAutoInsertHandler : AbstractStatelessRequestHandler csharpBraceCompletionServices, - [ImportMany(LanguageNames.VisualBasic)] IEnumerable visualBasicBraceCompletionServices, - IGlobalOptionService globalOptions) + [ImportMany(LanguageNames.VisualBasic)] IEnumerable visualBasicBraceCompletionServices) { _csharpBraceCompletionServices = csharpBraceCompletionServices.ToImmutableArray(); _visualBasicBraceCompletionServices = visualBasicBraceCompletionServices.ToImmutableArray(); - _globalOptions = globalOptions; } public override LSP.TextDocumentIdentifier? GetTextDocumentIdentifier(LSP.VSInternalDocumentOnAutoInsertParams request) => request.TextDocument; @@ -61,15 +58,16 @@ public OnAutoInsertHandler( var service = document.GetRequiredLanguageService(); // We should use the options passed in by LSP instead of the document's options. - var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, cancellationToken).ConfigureAwait(false); + var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync( + request.Options, document, cancellationToken).ConfigureAwait(false); + + var options = DocumentationCommentOptions.From(documentOptions); // The editor calls this handler for C# and VB comment characters, but we only need to process the one for the language that matches the document if (request.Character == "\n" || request.Character == service.DocumentationCommentCharacter) { - var docCommentOptions = _globalOptions.GetDocumentationCommentOptions(formattingOptions, document.Project.Language); - var documentationCommentResponse = await GetDocumentationCommentResponseAsync( - request, document, service, docCommentOptions, cancellationToken).ConfigureAwait(false); + request, document, service, options, cancellationToken).ConfigureAwait(false); if (documentationCommentResponse != null) { return documentationCommentResponse; @@ -81,7 +79,7 @@ public OnAutoInsertHandler( // Once LSP supports overtype we can move all of brace completion to LSP. if (request.Character == "\n" && context.ClientName == document.Services.GetService()?.DiagnosticsLspClientName) { - var indentationOptions = new IndentationOptions(formattingOptions, _globalOptions.GetAutoFormattingOptions(document.Project.Language)); + var indentationOptions = IndentationOptions.From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); var braceCompletionAfterReturnResponse = await GetBraceCompletionAfterReturnResponseAsync( request, document, indentationOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb b/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb index 7199cf45bd65a..bc75860e9b89a 100644 --- a/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb +++ b/src/Features/VisualBasic/Portable/Formatting/VisualBasicOrganizeUsingsNewDocumentFormattingProvider.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Public Sub New() End Sub - Public Function FormatNewDocumentAsync(document As Document, hintDocument As Document, options As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) Implements INewDocumentFormattingProvider.FormatNewDocumentAsync + Public Function FormatNewDocumentAsync(document As Document, hintDocument As Document, cancellationToken As CancellationToken) As Task(Of Document) Implements INewDocumentFormattingProvider.FormatNewDocumentAsync Return Formatter.OrganizeImportsAsync(document, cancellationToken) End Function End Class diff --git a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb index 9c1023c82aa28..5d843197b09b7 100644 --- a/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb +++ b/src/Features/VisualBasic/Portable/Wrapping/VisualBasicSyntaxWrappingOptions.vb @@ -6,7 +6,7 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Wrapping Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.VisualBasic.Formatting +Imports Microsoft.CodeAnalysis.Formatting Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping @@ -14,16 +14,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Wrapping Inherits SyntaxWrappingOptions Public Sub New( - formattingOptions As VisualBasicSyntaxFormattingOptions, + useTabs As Boolean, + tabSize As Integer, + newLine As String, wrappingColumn As Integer, operatorPlacement As OperatorPlacementWhenWrappingPreference) - MyBase.New(formattingOptions, wrappingColumn, operatorPlacement) + MyBase.New(useTabs, tabSize, newLine, wrappingColumn, operatorPlacement) End Sub Public Shared Function Create(options As AnalyzerConfigOptions, ideOptions As CodeActionOptions) As VisualBasicSyntaxWrappingOptions Return New VisualBasicSyntaxWrappingOptions( - VisualBasicSyntaxFormattingOptions.Create(options), + useTabs:=options.GetOption(FormattingOptions2.UseTabs), + tabSize:=options.GetOption(FormattingOptions2.TabSize), + newLine:=options.GetOption(FormattingOptions2.NewLine), operatorPlacement:=options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping), wrappingColumn:=ideOptions.WrappingColumn) End Function diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs index f8ccc3218be90..cdbd528c71867 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; @@ -38,22 +37,22 @@ public FSharpEditorFormattingService(IFSharpEditorFormattingService service) public bool SupportsFormatOnReturn => _service.SupportsFormatOnReturn; - public Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, CancellationToken cancellationToken) + public Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { return _service.GetFormattingChangesAsync(document, textSpan, cancellationToken); } - public Task?> GetFormattingChangesAsync(Document document, char typedChar, int position, CancellationToken cancellationToken) + public Task?> GetFormattingChangesAsync(Document document, char typedChar, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { return _service.GetFormattingChangesAsync(document, typedChar, position, cancellationToken); } - public Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public Task> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { return _service.GetFormattingChangesOnPasteAsync(document, textSpan, cancellationToken); } - public Task?> GetFormattingChangesOnReturnAsync(Document document, int position, CancellationToken cancellationToken) + public Task?> GetFormattingChangesOnReturnAsync(Document document, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { return _service.GetFormattingChangesOnReturnAsync(document, position, cancellationToken); } @@ -65,27 +64,27 @@ public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormatting _service.SupportsFormattingOnTypedCharacter(document, ch); } - async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, TextSpan? textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken) + async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, TextSpan? textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - var changes = await GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var changes = await GetFormattingChangesAsync(document, textSpan, documentOptions, cancellationToken).ConfigureAwait(false); return changes?.ToImmutableArray() ?? ImmutableArray.Empty; } - async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, char typedChar, int position, IndentationOptions options, CancellationToken cancellationToken) + async Task> IFormattingInteractionService.GetFormattingChangesAsync(Document document, char typedChar, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - var changes = await GetFormattingChangesAsync(document, typedChar, position, cancellationToken).ConfigureAwait(false); + var changes = await GetFormattingChangesAsync(document, typedChar, position, documentOptions, cancellationToken).ConfigureAwait(false); return changes?.ToImmutableArray() ?? ImmutableArray.Empty; } - async Task> IFormattingInteractionService.GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken) + async Task> IFormattingInteractionService.GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - var changes = await GetFormattingChangesOnPasteAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var changes = await GetFormattingChangesOnPasteAsync(document, textSpan, documentOptions, cancellationToken).ConfigureAwait(false); return changes?.ToImmutableArray() ?? ImmutableArray.Empty; } - async Task> IFormattingInteractionService.GetFormattingChangesOnReturnAsync(Document document, int position, CancellationToken cancellationToken) + async Task> IFormattingInteractionService.GetFormattingChangesOnReturnAsync(Document document, int position, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - var changes = await GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(false); + var changes = await GetFormattingChangesOnReturnAsync(document, position, documentOptions, cancellationToken).ConfigureAwait(false); return changes?.ToImmutableArray() ?? ImmutableArray.Empty; } } diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSynchronousIndentationService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSynchronousIndentationService.cs index 9ef917f04242a..ace8ede5fb0a5 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSynchronousIndentationService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpSynchronousIndentationService.cs @@ -34,7 +34,7 @@ public FSharpSynchronousIndentationService( _service = service; } - public IndentationResult GetIndentation(Document document, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) + public IndentationResult GetIndentation(Document document, int lineNumber, FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) { // all F# documents should have a file path if (document.FilePath == null) @@ -46,12 +46,13 @@ public IndentationResult GetIndentation(Document document, int lineNumber, Inden if (_service != null) { var text = document.GetTextSynchronously(cancellationToken); + var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); - var fsharpOptions = new FSharpIndentationOptions( - TabSize: options.FormattingOptions.TabSize, - IndentStyle: options.AutoFormattingOptions.IndentStyle); + var options = new FSharpIndentationOptions( + TabSize: documentOptions.GetOption(FormattingOptions.TabSize, LanguageNames.FSharp), + IndentStyle: indentStyle); - result = _service.GetDesiredIndentation(document.Project.LanguageServices, text, document.Id, document.FilePath, lineNumber, fsharpOptions); + result = _service.GetDesiredIndentation(document.Project.LanguageServices, text, document.Id, document.FilePath, lineNumber, options); } else { diff --git a/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs b/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs index 2a1259aa52ca9..29cd5c5a935a4 100644 --- a/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs +++ b/src/Tools/ExternalAccess/OmniSharp/DocumentationComments/OmniSharpDocumentationCommentOptionsWrapper.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.DocumentationComments { @@ -30,13 +29,8 @@ public static async ValueTask FromD bool autoXmlDocCommentGeneration, CancellationToken cancellationToken) { - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - - return new(new DocumentationCommentOptions( - AutoXmlDocCommentGeneration: autoXmlDocCommentGeneration, - TabSize: formattingOptions.TabSize, - UseTabs: formattingOptions.UseTabs, - NewLine: formattingOptions.NewLine)); + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + return new(DocumentationCommentOptions.From(documentOptions) with { AutoXmlDocCommentGeneration = autoXmlDocCommentGeneration }); } } } diff --git a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj index e56e00c7d76cf..a1434a15de1f6 100644 --- a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj +++ b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj @@ -14,10 +14,6 @@ - - - - @@ -26,7 +22,7 @@ --> - + diff --git a/src/Tools/ExternalAccess/Razor/RazorAutoFormattingOptions.cs b/src/Tools/ExternalAccess/Razor/RazorAutoFormattingOptions.cs deleted file mode 100644 index 8862f8eefb4b7..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorAutoFormattingOptions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Formatting; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal readonly struct RazorAutoFormattingOptions - { - internal readonly AutoFormattingOptions UnderlyingObject; - - public RazorAutoFormattingOptions(AutoFormattingOptions underlyingObject) - => UnderlyingObject = underlyingObject; - - public RazorAutoFormattingOptions( - FormattingOptions.IndentStyle indentStyle, - bool formatOnReturn, - bool formatOnTyping, - bool formatOnSemicolon, - bool formatOnCloseBrace) - : this(new AutoFormattingOptions( - indentStyle, - FormatOnReturn: formatOnReturn, - FormatOnTyping: formatOnTyping, - FormatOnSemicolon: formatOnSemicolon, - FormatOnCloseBrace: formatOnCloseBrace)) - { - } - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs index 016a619c673be..164758b6f3031 100644 --- a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs +++ b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs @@ -2,15 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -24,29 +19,30 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Razor internal static class RazorCSharpFormattingInteractionService { /// - /// Returns the text changes necessary to format the document after the user enters a - /// character. The position provided is the position of the caret in the document after - /// the character been inserted into the document. + /// True if this service would like to format the document based on the user typing the + /// provided character. + /// + public static bool SupportsFormattingOnTypedCharacter(Document document, char ch) + { + Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); + var formattingService = document.GetRequiredLanguageService(); + var options = AutoFormattingOptions.From(document.Project); + return formattingService.SupportsFormattingOnTypedCharacter(document, options, ch); + } + + /// + /// Returns the text changes necessary to format the document. If "textSpan" is provided, + /// only the text changes necessary to format that span are needed. /// - [Obsolete("Use the other overload")] public static Task> GetFormattingChangesAsync( Document document, - char typedChar, - int position, - DocumentOptionSet documentOptions, + TextSpan? textSpan, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); var formattingService = document.GetRequiredLanguageService(); - var services = document.Project.Solution.Workspace.Services; - - var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService(); - - var indentationOptions = new IndentationOptions( - SyntaxFormattingOptions.Create(documentOptions, services, document.Project.Language), - globalOptions.GlobalOptions.GetAutoFormattingOptions(document.Project.Language)); - - return formattingService.GetFormattingChangesAsync(document, typedChar, position, indentationOptions, cancellationToken); + return formattingService.GetFormattingChangesAsync(document, textSpan, documentOptions, cancellationToken); } /// @@ -54,48 +50,45 @@ public static Task> GetFormattingChangesAsync( /// character. The position provided is the position of the caret in the document after /// the character been inserted into the document. /// - public static async Task> GetFormattingChangesAsync( + public static Task> GetFormattingChangesAsync( Document document, char typedChar, int position, - RazorIndentationOptions indentationOptions, - RazorAutoFormattingOptions autoFormattingOptions, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); var formattingService = document.GetRequiredLanguageService(); - - var formattingOptions = GetFormattingOptions(indentationOptions); - var roslynIndentationOptions = new IndentationOptions(formattingOptions, autoFormattingOptions.UnderlyingObject); - - return await formattingService.GetFormattingChangesAsync(document, typedChar, position, roslynIndentationOptions, cancellationToken).ConfigureAwait(false); + return formattingService.GetFormattingChangesAsync(document, typedChar, position, documentOptions, cancellationToken); } - public static IList GetFormattedTextChanges( - HostWorkspaceServices services, - SyntaxNode root, - TextSpan span, - RazorIndentationOptions indentationOptions, + /// + /// Returns the text changes necessary to format the document on paste operation. + /// + public static Task> GetFormattingChangesOnPasteAsync( + Document document, + TextSpan textSpan, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - Contract.ThrowIfFalse(root.Language is LanguageNames.CSharp); - return Formatter.GetFormattedTextChanges(root, span, services, GetFormattingOptions(indentationOptions), cancellationToken); + Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); + var formattingService = document.GetRequiredLanguageService(); + return formattingService.GetFormattingChangesOnPasteAsync(document, textSpan, documentOptions, cancellationToken); } - public static SyntaxNode Format( - HostWorkspaceServices services, - SyntaxNode root, - RazorIndentationOptions indentationOptions, + /// + /// Returns the text changes necessary to format the document after the user enters a Return + /// The position provided is the position of the caret in the document after Return. + /// + public static Task> GetFormattingChangesOnReturnAsync( + Document document, + int position, + DocumentOptionSet? documentOptions, CancellationToken cancellationToken) { - Contract.ThrowIfFalse(root.Language is LanguageNames.CSharp); - return Formatter.Format(root, services, GetFormattingOptions(indentationOptions), cancellationToken: cancellationToken); + Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); + var formattingService = document.GetRequiredLanguageService(); + return formattingService.GetFormattingChangesOnReturnAsync(document, position, documentOptions, cancellationToken); } - - private static SyntaxFormattingOptions GetFormattingOptions(RazorIndentationOptions indentationOptions) - => CSharpSyntaxFormattingOptions.Default.With( - useTabs: indentationOptions.UseTabs, - tabSize: indentationOptions.TabSize, - indentationSize: indentationOptions.IndentationSize); } } diff --git a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs b/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs deleted file mode 100644 index aff73c5aa9c12..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Formatting; -using System.Linq; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - [Export(typeof(RazorGlobalOptions)), Shared] - internal sealed class RazorGlobalOptions - { - private readonly IGlobalOptionService _globalOptions; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorGlobalOptions(IGlobalOptionService globalOptions) - { - _globalOptions = globalOptions; - } - - /// - /// For testing purposes. - /// - public static RazorGlobalOptions GetGlobalOptions(Workspace workspace) - => ((IMefHostExportProvider)workspace.Services.HostServices).GetExports().Single().Value; - - public RazorAutoFormattingOptions GetAutoFormattingOptions() - => new(_globalOptions.GetAutoFormattingOptions(LanguageNames.CSharp)); - } -} diff --git a/src/Tools/ExternalAccess/Razor/RazorIndentationOptions.cs b/src/Tools/ExternalAccess/Razor/RazorIndentationOptions.cs deleted file mode 100644 index d8097d9737517..0000000000000 --- a/src/Tools/ExternalAccess/Razor/RazorIndentationOptions.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor -{ - internal readonly record struct RazorIndentationOptions( - bool UseTabs, - int TabSize, - int IndentationSize); -} diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 97f185ae57102..16158626d8710 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -85,7 +85,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(Show_guides_for_declaration_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp); BindToOption(Show_guides_for_code_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp); - BindToOption(GenerateXmlDocCommentsForTripleSlash, DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, LanguageNames.CSharp); + BindToOption(GenerateXmlDocCommentsForTripleSlash, DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration, LanguageNames.CSharp); BindToOption(InsertSlashSlashAtTheStartOfNewLinesWhenWritingSingleLineComments, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp); BindToOption(InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments, FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp); diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs index 08609e84d67c3..4e2bea903475a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs @@ -10,8 +10,8 @@ public partial class AutomationObject { public int Formatting_TriggerOnBlockCompletion { - get { return GetBooleanOption(AutoFormattingOptionsStorage.FormatOnCloseBrace); } - set { SetBooleanOption(AutoFormattingOptionsStorage.FormatOnCloseBrace, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.cs index 07edfda789d98..bbb6774dfce9a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.cs @@ -10,8 +10,8 @@ public partial class AutomationObject { public int AutoComment { - get { return GetBooleanOption(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration); } - set { SetBooleanOption(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, value); } + get { return GetBooleanOption(DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration); } + set { SetBooleanOption(DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs index 3eb0b9da1ba1d..237bb96935b39 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs @@ -311,14 +311,14 @@ public int Formatting_TriggerOnPaste public int Formatting_TriggerOnStatementCompletion { - get { return GetBooleanOption(AutoFormattingOptionsStorage.FormatOnSemicolon); } - set { SetBooleanOption(AutoFormattingOptionsStorage.FormatOnSemicolon, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, value); } } public int AutoFormattingOnTyping { - get { return GetBooleanOption(AutoFormattingOptionsStorage.FormatOnTyping); } - set { SetBooleanOption(AutoFormattingOptionsStorage.FormatOnTyping, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnTyping); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs index ce557577dabdf..63d3f9f7544c9 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs @@ -32,10 +32,10 @@ public FormattingOptionPageControl(OptionStore optionStore) : base(optionStore) FormatOnReturnCheckBox.Content = CSharpVSResources.Automatically_format_on_return; FormatOnPasteCheckBox.Content = CSharpVSResources.Automatically_format_on_paste; - BindToOption(FormatWhenTypingCheckBox, AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp); - BindToOption(FormatOnCloseBraceCheckBox, AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp); - BindToOption(FormatOnSemicolonCheckBox, AutoFormattingOptionsStorage.FormatOnSemicolon, LanguageNames.CSharp); - BindToOption(FormatOnReturnCheckBox, AutoFormattingOptionsStorage.FormatOnReturn, LanguageNames.CSharp); + BindToOption(FormatWhenTypingCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp); + BindToOption(FormatOnCloseBraceCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp); + BindToOption(FormatOnSemicolonCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, LanguageNames.CSharp); + BindToOption(FormatOnReturnCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnReturn, LanguageNames.CSharp); BindToOption(FormatOnPasteCheckBox, FormattingOptionsMetadata.FormatOnPaste, LanguageNames.CSharp); } } diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs index e24212d375677..90c281549b465 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs @@ -320,16 +320,15 @@ private async Task FormatDocumentCreatedFromTemplateAsync(IVsHierarchy hierarchy var forkedSolution = projectToAddTo.Solution.AddDocument(DocumentInfo.Create(documentId, filePath, loader: new FileTextLoader(filePath, defaultEncoding: null), filePath: filePath)); var addedDocument = forkedSolution.GetDocument(documentId)!; - var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(addedDocument, cancellationToken).ConfigureAwait(true); - // Call out to various new document formatters to tweak what they want var formattingService = addedDocument.GetLanguageService(); if (formattingService is not null) { - addedDocument = await formattingService.FormatNewDocumentAsync(addedDocument, hintDocument: null, formattingOptions, cancellationToken).ConfigureAwait(true); + addedDocument = await formattingService.FormatNewDocumentAsync(addedDocument, hintDocument: null, cancellationToken).ConfigureAwait(true); } var rootToFormat = await addedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(true); + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(addedDocument, cancellationToken).ConfigureAwait(true); // Format document var unformattedText = await addedDocument.GetTextAsync(cancellationToken).ConfigureAwait(true); diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb index 0bd8b030dcaf7..fc5084c04f87c 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb @@ -96,7 +96,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options BindToOption(Show_guides_for_code_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.VisualBasic) ' Comments - BindToOption(GenerateXmlDocCommentsForTripleApostrophes, DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, LanguageNames.VisualBasic) + BindToOption(GenerateXmlDocCommentsForTripleApostrophes, DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration, LanguageNames.VisualBasic) BindToOption(InsertApostropheAtTheStartOfNewLinesWhenWritingApostropheComments, SplitCommentOptions.Enabled, LanguageNames.VisualBasic) ' Editor help diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.vb b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.vb index ce8e742f389ff..c86201b189caa 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject/AutomationObject.DocumentationComment.vb @@ -8,10 +8,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Partial Public Class AutomationObject Public Property AutoComment As Boolean Get - Return GetBooleanOption(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration) + Return GetBooleanOption(DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration) End Get Set(value As Boolean) - SetBooleanOption(DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, value) + SetBooleanOption(DocumentationCommentOptions.Metadata.AutoXmlDocCommentGeneration, value) End Set End Property End Class diff --git a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj index edae5aac3bae6..fb0483f25a55e 100644 --- a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj +++ b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj @@ -47,7 +47,6 @@ - diff --git a/src/Workspaces/Core/Portable/Formatting/AutoFormattingOptions.cs b/src/Workspaces/Core/Portable/Formatting/AutoFormattingOptions.cs index ecaa58d401bf8..edc1df9610d0e 100644 --- a/src/Workspaces/Core/Portable/Formatting/AutoFormattingOptions.cs +++ b/src/Workspaces/Core/Portable/Formatting/AutoFormattingOptions.cs @@ -2,25 +2,73 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Runtime.Serialization; - -namespace Microsoft.CodeAnalysis.Formatting; - -/// -/// Automatic formatting options. -/// -[DataContract] -internal readonly record struct AutoFormattingOptions( - [property: DataMember(Order = 0)] FormattingOptions.IndentStyle IndentStyle = FormattingOptions.IndentStyle.Smart, - [property: DataMember(Order = 1)] bool FormatOnReturn = true, - [property: DataMember(Order = 2)] bool FormatOnTyping = true, - [property: DataMember(Order = 3)] bool FormatOnSemicolon = true, - [property: DataMember(Order = 4)] bool FormatOnCloseBrace = true) +using System; +using System.Collections.Immutable; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Options.Providers; + +namespace Microsoft.CodeAnalysis.Formatting { - public AutoFormattingOptions() - : this(IndentStyle: FormattingOptions.IndentStyle.Smart) + /// + /// Solution-wide formatting options. + /// + internal readonly record struct AutoFormattingOptions( + FormattingOptions.IndentStyle IndentStyle, + bool FormatOnReturn, + bool FormatOnTyping, + bool FormatOnSemicolon, + bool FormatOnCloseBrace) { - } + public static AutoFormattingOptions From(Project project) + => From(project.Solution.Options, project.Language); + + public static AutoFormattingOptions From(OptionSet options, string language) + => new( + IndentStyle: options.GetOption(Metadata.SmartIndent, language), + FormatOnReturn: options.GetOption(Metadata.AutoFormattingOnReturn, language), + FormatOnTyping: options.GetOption(Metadata.AutoFormattingOnTyping, language), + FormatOnSemicolon: options.GetOption(Metadata.AutoFormattingOnSemicolon, language), + FormatOnCloseBrace: options.GetOption(Metadata.AutoFormattingOnCloseBrace, language)); + + [ExportSolutionOptionProvider, Shared] + internal sealed class Metadata : IOptionProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public Metadata() + { + } + + public ImmutableArray Options { get; } = ImmutableArray.Create( + SmartIndent, + AutoFormattingOnReturn, + AutoFormattingOnTyping, + AutoFormattingOnSemicolon, + AutoFormattingOnCloseBrace); + + private const string FeatureName = "FormattingOptions"; - public static readonly AutoFormattingOptions Default = new(); + // This is also serialized by the Visual Studio-specific LanguageSettingsPersister + public static PerLanguageOption2 SmartIndent { get; } = + new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(SmartIndent), defaultValue: FormattingOptions.IndentStyle.Smart); + + internal static readonly PerLanguageOption2 AutoFormattingOnReturn = + new(FeatureName, OptionGroup.Default, nameof(AutoFormattingOnReturn), defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Return")); + + public static readonly PerLanguageOption2 AutoFormattingOnTyping = + new(FeatureName, OptionGroup.Default, nameof(AutoFormattingOnTyping), defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Typing")); + + public static readonly PerLanguageOption2 AutoFormattingOnSemicolon = + new(FeatureName, OptionGroup.Default, nameof(AutoFormattingOnSemicolon), defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Semicolon")); + + public static readonly PerLanguageOption2 AutoFormattingOnCloseBrace = new( + "BraceCompletionOptions", nameof(AutoFormattingOnCloseBrace), defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Close Brace")); + } + } } diff --git a/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs b/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs index 1fe0b8c37206c..25ddf34780753 100644 --- a/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs +++ b/src/Workspaces/Core/Portable/Formatting/FormattingOptions.cs @@ -21,17 +21,12 @@ public static partial class FormattingOptions // Suppression due to https://github.com/dotnet/roslyn/issues/42614 public static PerLanguageOption IndentationSize { get; } = ((PerLanguageOption)FormattingOptions2.IndentationSize)!; - /// + /// // Suppression due to https://github.com/dotnet/roslyn/issues/42614 - public static PerLanguageOption NewLine { get; } = ((PerLanguageOption)FormattingOptions2.NewLine)!; - - // This is also serialized by the Visual Studio-specific LanguageSettingsPersister + public static PerLanguageOption SmartIndent { get; } = ((PerLanguageOption)AutoFormattingOptions.Metadata.SmartIndent)!; - internal static readonly PerLanguageOption2 SmartIndent2 = new( - "FormattingOptions", FormattingOptionGroups.IndentationAndSpacing, "SmartIndent", defaultValue: IndentStyle.Smart); - - /// + /// // Suppression due to https://github.com/dotnet/roslyn/issues/42614 - public static PerLanguageOption SmartIndent { get; } = (PerLanguageOption)SmartIndent2!; + public static PerLanguageOption NewLine { get; } = ((PerLanguageOption)FormattingOptions2.NewLine)!; } } diff --git a/src/Workspaces/Core/Portable/Indentation/AbstractIndentationService.cs b/src/Workspaces/Core/Portable/Indentation/AbstractIndentationService.cs index 717cf7af07146..3c6655866c34f 100644 --- a/src/Workspaces/Core/Portable/Indentation/AbstractIndentationService.cs +++ b/src/Workspaces/Core/Portable/Indentation/AbstractIndentationService.cs @@ -30,10 +30,10 @@ private IEnumerable GetFormattingRules(Document document } public IndentationResult GetIndentation( - Document document, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) + Document document, int lineNumber, + FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) { - var indenter = GetIndenter(document, lineNumber, options, cancellationToken); - var indentStyle = options.AutoFormattingOptions.IndentStyle; + var indenter = GetIndenter(document, lineNumber, indentStyle, cancellationToken); if (indentStyle == FormattingOptions.IndentStyle.None) { @@ -51,14 +51,15 @@ public IndentationResult GetIndentation( return indenter.GetDesiredIndentation(indentStyle) ?? default; } - private Indenter GetIndenter(Document document, int lineNumber, IndentationOptions options, CancellationToken cancellationToken) + private Indenter GetIndenter(Document document, int lineNumber, FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) { + var options = IndentationOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); var syntacticDoc = SyntacticDocument.CreateAsync(document, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); var sourceText = syntacticDoc.Root.SyntaxTree.GetText(cancellationToken); var lineToBeIndented = sourceText.Lines[lineNumber]; - var formattingRules = GetFormattingRules(document, lineToBeIndented.Start, options.AutoFormattingOptions.IndentStyle); + var formattingRules = GetFormattingRules(document, lineToBeIndented.Start, indentStyle); return new Indenter(this, syntacticDoc, formattingRules, options, lineToBeIndented, cancellationToken); } diff --git a/src/Workspaces/Core/Portable/Indentation/DefaultInferredIndentationService.cs b/src/Workspaces/Core/Portable/Indentation/DefaultInferredIndentationService.cs new file mode 100644 index 0000000000000..df5b50dce3a25 --- /dev/null +++ b/src/Workspaces/Core/Portable/Indentation/DefaultInferredIndentationService.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Indentation +{ + [ExportWorkspaceService(typeof(IInferredIndentationService), ServiceLayer.Default), Shared] + internal sealed class DefaultInferredIndentationService + : IInferredIndentationService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DefaultInferredIndentationService() + { + } + + public Task GetDocumentOptionsWithInferredIndentationAsync(Document document, bool explicitFormat, CancellationToken cancellationToken) + { + // The workspaces layer doesn't have any smarts to infer spaces/tabs settings without an editorconfig, so just return + // the document's options. + return document.GetOptionsAsync(cancellationToken); + } + } +} diff --git a/src/Workspaces/Core/Portable/Indentation/IIndentationService.cs b/src/Workspaces/Core/Portable/Indentation/IIndentationService.cs index 2f61835c62174..bded4bc6cc168 100644 --- a/src/Workspaces/Core/Portable/Indentation/IIndentationService.cs +++ b/src/Workspaces/Core/Portable/Indentation/IIndentationService.cs @@ -50,16 +50,28 @@ internal interface IIndentationService : ILanguageService /// /// Determines the desired indentation of a given line. /// - IndentationResult GetIndentation(Document document, int lineNumber, IndentationOptions options, CancellationToken cancellationToken); + IndentationResult GetIndentation( + Document document, int lineNumber, + FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken); } internal static class IIndentationServiceExtensions { + public static IndentationResult GetIndentation( + this IIndentationService service, Document document, + int lineNumber, CancellationToken cancellationToken) + { + var options = document.GetOptionsAsync(cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); + var style = options.GetOption(FormattingOptions.SmartIndent, document.Project.Language); + + return service.GetIndentation(document, lineNumber, style, cancellationToken); + } + /// /// Get's the preferred indentation for if that token were on its own line. This /// effectively simulates where the token would be if the user hit enter at the start of the token. /// - public static string GetPreferredIndentation(this SyntaxToken token, Document document, IndentationOptions options, CancellationToken cancellationToken) + public static string GetPreferredIndentation(this SyntaxToken token, Document document, CancellationToken cancellationToken) { var sourceText = document.GetTextSynchronously(cancellationToken); var tokenLine = sourceText.Lines.GetLineFromPosition(token.SpanStart); @@ -74,11 +86,15 @@ public static string GetPreferredIndentation(this SyntaxToken token, Document do // Token was on a line with something else. Determine where we would indent the token if it was on the next // line and use that to determine the indentation of the final line. + var options = document.Project.Solution.Options; + var languageName = document.Project.Language; + var newLine = options.GetOption(FormattingOptions.NewLine, languageName); + var annotation = new SyntaxAnnotation(); var newToken = token.WithAdditionalAnnotations(annotation); var syntaxGenerator = document.GetRequiredLanguageService(); - newToken = newToken.WithLeadingTrivia(newToken.LeadingTrivia.Add(syntaxGenerator.EndOfLine(options.FormattingOptions.NewLine))); + newToken = newToken.WithLeadingTrivia(newToken.LeadingTrivia.Add(syntaxGenerator.EndOfLine(newLine))); var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); var newRoot = root.ReplaceToken(token, newToken); @@ -87,13 +103,15 @@ public static string GetPreferredIndentation(this SyntaxToken token, Document do var newTokenLine = newText.Lines.GetLineFromPosition(newRoot.GetAnnotatedTokens(annotation).Single().SpanStart); + var indentStyle = document.Project.Solution.Options.GetOption(FormattingOptions.SmartIndent, languageName); var indenter = document.GetRequiredLanguageService(); - var indentation = indenter.GetIndentation(newDocument, newTokenLine.LineNumber, options, cancellationToken); + + var indentation = indenter.GetIndentation(newDocument, newTokenLine.LineNumber, indentStyle, cancellationToken); return indentation.GetIndentationString( newText, - options.FormattingOptions.UseTabs, - options.FormattingOptions.TabSize); + options.GetOption(FormattingOptions.UseTabs, languageName), + options.GetOption(FormattingOptions.TabSize, languageName)); } } diff --git a/src/Workspaces/Core/Portable/Indentation/IInferredIndentationService.cs b/src/Workspaces/Core/Portable/Indentation/IInferredIndentationService.cs new file mode 100644 index 0000000000000..1acc3d60ff49f --- /dev/null +++ b/src/Workspaces/Core/Portable/Indentation/IInferredIndentationService.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Indentation +{ + /// + /// Gets the correct indentation to be used for the document. Depending on the host, there may be smarts to compensate for lack of an editorconfig if there + /// isn't one present. + /// + internal interface IInferredIndentationService : IWorkspaceService + { + Task GetDocumentOptionsWithInferredIndentationAsync(Document document, bool explicitFormat, CancellationToken cancellationToken); + } +} diff --git a/src/Workspaces/Core/Portable/Indentation/IndentationOptions.cs b/src/Workspaces/Core/Portable/Indentation/IndentationOptions.cs index 53da18d122bde..b60fa4f7bc537 100644 --- a/src/Workspaces/Core/Portable/Indentation/IndentationOptions.cs +++ b/src/Workspaces/Core/Portable/Indentation/IndentationOptions.cs @@ -4,13 +4,25 @@ using System.Threading; using System.Threading.Tasks; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Indentation { - [DataContract] internal readonly record struct IndentationOptions( - [property: DataMember(Order = 0)] SyntaxFormattingOptions FormattingOptions, - [property: DataMember(Order = 1)] AutoFormattingOptions AutoFormattingOptions); + SyntaxFormattingOptions FormattingOptions, + AutoFormattingOptions AutoFormattingOptions) + { + public static async Task FromDocumentAsync(Document document, CancellationToken cancellationToken) + { + var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + return From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); + } + + public static IndentationOptions From(OptionSet options, HostWorkspaceServices services, string language) + => new( + SyntaxFormattingOptions.Create(options, services, language), + AutoFormattingOptions.From(options, language)); + } } diff --git a/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs index 1dba460027b2a..68f7362c24c13 100644 --- a/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs @@ -24,8 +24,6 @@ internal DocumentOptionSet(OptionSet backingOptionSet, string language) _language = language; } - internal string Language => _language; - private protected override object? GetOptionCore(OptionKey optionKey) => _backingOptionSet.GetOption(optionKey); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs index 79f0c214c8550..2f9451e7e3fff 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpSyntaxFormattingOptions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -68,28 +67,14 @@ internal enum IndentationPlacement SwitchSection = 1 << 4 } - [DataContract] internal sealed class CSharpSyntaxFormattingOptions : SyntaxFormattingOptions { - [DataMember(Order = BaseMemberCount + 0)] public readonly SpacePlacement Spacing; - - [DataMember(Order = BaseMemberCount + 1)] public readonly BinaryOperatorSpacingOptions SpacingAroundBinaryOperator; - - [DataMember(Order = BaseMemberCount + 2)] public readonly NewLinePlacement NewLines; - - [DataMember(Order = BaseMemberCount + 3)] public readonly LabelPositionOptions LabelPositioning; - - [DataMember(Order = BaseMemberCount + 4)] public readonly IndentationPlacement Indentation; - - [DataMember(Order = BaseMemberCount + 5)] public readonly bool WrappingKeepStatementsOnSingleLine; - - [DataMember(Order = BaseMemberCount + 6)] public readonly bool WrappingPreserveSingleLine; public CSharpSyntaxFormattingOptions( @@ -233,20 +218,5 @@ public static CSharpSyntaxFormattingOptions Create(AnalyzerConfigOptions options (options.GetOption(CSharpFormattingOptions2.IndentSwitchSection) ? IndentationPlacement.SwitchSection : 0), wrappingKeepStatementsOnSingleLine: options.GetOption(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine), wrappingPreserveSingleLine: options.GetOption(CSharpFormattingOptions2.WrappingPreserveSingleLine)); - - public override SyntaxFormattingOptions With(bool useTabs, int tabSize, int indentationSize) - => new CSharpSyntaxFormattingOptions( - useTabs: useTabs, - tabSize: tabSize, - indentationSize: indentationSize, - NewLine, - SeparateImportDirectiveGroups, - Spacing, - SpacingAroundBinaryOperator, - NewLines, - LabelPositioning, - Indentation, - WrappingKeepStatementsOnSingleLine, - WrappingPreserveSingleLine); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormattingService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormattingService.cs index ccf7dd4cf0fb5..c83b980861bbe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormattingService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/ISyntaxFormattingService.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Diagnostics; -using System.Runtime.Serialization; -using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Options; #if !CODE_STYLE @@ -27,26 +27,15 @@ internal interface ISyntaxFormattingService IFormattingResult GetFormattingResult(SyntaxNode node, IEnumerable? spans, SyntaxFormattingOptions options, IEnumerable? rules, CancellationToken cancellationToken); } - [DataContract] internal abstract class SyntaxFormattingOptions { - [DataMember(Order = 0)] public readonly bool UseTabs; - - [DataMember(Order = 1)] public readonly int TabSize; - - [DataMember(Order = 2)] public readonly int IndentationSize; - - [DataMember(Order = 3)] public readonly string NewLine; - [DataMember(Order = 4)] public readonly bool SeparateImportDirectiveGroups; - protected const int BaseMemberCount = 5; - protected SyntaxFormattingOptions( bool useTabs, int tabSize, @@ -61,8 +50,6 @@ protected SyntaxFormattingOptions( SeparateImportDirectiveGroups = separateImportDirectiveGroups; } - public abstract SyntaxFormattingOptions With(bool useTabs, int tabSize, int indentationSize); - #if !CODE_STYLE public static SyntaxFormattingOptions Create(OptionSet options, HostWorkspaceServices services, string language) { diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb index d1f004738a274..8c7f1ee5c89f3 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/VisualBasicSyntaxFormattingOptions.vb @@ -2,13 +2,11 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Runtime.Serialization Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting - Friend NotInheritable Class VisualBasicSyntaxFormattingOptions Inherits SyntaxFormattingOptions @@ -40,14 +38,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting newLine:=options.GetOption(FormattingOptions2.NewLine), separateImportDirectiveGroups:=options.GetOption(GenerationOptions.SeparateImportDirectiveGroups)) End Function - - Public Overrides Function [With](useTabs As Boolean, tabSize As Integer, indentationSize As Integer) As SyntaxFormattingOptions - Return New VisualBasicSyntaxFormattingOptions( - useTabs:=useTabs, - tabSize:=tabSize, - indentationSize:=indentationSize, - newLine:=NewLine, - separateImportDirectiveGroups:=SeparateImportDirectiveGroups) - End Function End Class End Namespace