未验证 提交 ead48848 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #33983 from CyrusNajmabadi/simplifyEnterHandling

Simplify handling of 'enter' in formatting.
...@@ -39,7 +39,7 @@ public CSharpEditorFormattingService() ...@@ -39,7 +39,7 @@ public CSharpEditorFormattingService()
public bool SupportsFormatDocument => true; public bool SupportsFormatDocument => true;
public bool SupportsFormatOnPaste => true; public bool SupportsFormatOnPaste => true;
public bool SupportsFormatSelection => true; public bool SupportsFormatSelection => true;
public bool SupportsFormatOnReturn => true; public bool SupportsFormatOnReturn => false;
public bool SupportsFormattingOnTypedCharacter(Document document, char ch) public bool SupportsFormattingOnTypedCharacter(Document document, char ch)
{ {
...@@ -125,53 +125,11 @@ private IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document ...@@ -125,53 +125,11 @@ private IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document
{ {
var workspace = document.Project.Solution.Workspace; var workspace = document.Project.Solution.Workspace;
var formattingRuleFactory = workspace.Services.GetService<IHostDependentFormattingRuleFactoryService>(); var formattingRuleFactory = workspace.Services.GetService<IHostDependentFormattingRuleFactoryService>();
return formattingRuleFactory.CreateRule(document, position).Concat(GetTypingRules(document, tokenBeforeCaret)).Concat(Formatter.GetDefaultFormattingRules(document)); return formattingRuleFactory.CreateRule(document, position).Concat(GetTypingRules(tokenBeforeCaret)).Concat(Formatter.GetDefaultFormattingRules(document));
} }
public async Task<IList<TextChange>> GetFormattingChangesOnReturnAsync(Document document, int caretPosition, CancellationToken cancellationToken) Task<IList<TextChange>> IEditorFormattingService.GetFormattingChangesOnReturnAsync(Document document, int caretPosition, CancellationToken cancellationToken)
{ => SpecializedTasks.Default<IList<TextChange>>();
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
if (!options.GetOption(FeatureOnOffOptions.AutoFormattingOnReturn))
{
return null;
}
// first, find the token user just typed.
SyntaxToken token = await GetTokenBeforeTheCaretAsync(document, caretPosition, cancellationToken).ConfigureAwait(false);
if (token.IsMissing)
{
return null;
}
var formattingRules = this.GetFormattingRules(document, caretPosition, token);
string text = null;
if (IsInvalidToken(token, ref text))
{
return null;
}
// Check to see if the token is ')' and also the parent is a using statement. If not, bail
if (TokenShouldNotFormatOnReturn(token))
{
return null;
}
// if formatting range fails, do format token one at least
var changes = await FormatRangeAsync(document, token, formattingRules, cancellationToken).ConfigureAwait(false);
if (changes.Count > 0)
{
return changes;
}
// if we can't, do normal smart indentation
return await FormatTokenAsync(document, token, formattingRules, cancellationToken).ConfigureAwait(false);
}
private static bool TokenShouldNotFormatOnReturn(SyntaxToken token)
{
return !token.IsKind(SyntaxKind.CloseParenToken) || !token.Parent.IsKind(SyntaxKind.UsingStatement);
}
private static async Task<bool> TokenShouldNotFormatOnTypeCharAsync( private static async Task<bool> TokenShouldNotFormatOnTypeCharAsync(
SyntaxToken token, CancellationToken cancellationToken) SyntaxToken token, CancellationToken cancellationToken)
...@@ -354,7 +312,7 @@ private ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnu ...@@ -354,7 +312,7 @@ private ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnu
return changes; return changes;
} }
private IEnumerable<AbstractFormattingRule> GetTypingRules(Document document, SyntaxToken tokenBeforeCaret) private IEnumerable<AbstractFormattingRule> GetTypingRules(SyntaxToken tokenBeforeCaret)
{ {
// Typing introduces several challenges around formatting. // Typing introduces several challenges around formatting.
// Historically we've shipped several triggers that cause formatting to happen directly while typing. // Historically we've shipped several triggers that cause formatting to happen directly while typing.
...@@ -464,33 +422,6 @@ private bool ValidSingleOrMultiCharactersTokenKind(char typedChar, SyntaxKind ki ...@@ -464,33 +422,6 @@ private bool ValidSingleOrMultiCharactersTokenKind(char typedChar, SyntaxKind ki
} }
} }
private bool IsInvalidToken(char typedChar, SyntaxToken token)
{
string text = null;
if (IsInvalidToken(token, ref text))
{
return true;
}
return text[0] != typedChar;
}
private bool IsInvalidToken(SyntaxToken token, ref string text)
{
if (IsInvalidTokenKind(token))
{
return true;
}
text = token.ToString();
if (text.Length != 1)
{
return true;
}
return false;
}
private bool IsInvalidTokenKind(SyntaxToken token) private bool IsInvalidTokenKind(SyntaxToken token)
{ {
// invalid token to be formatted // invalid token to be formatted
......
...@@ -119,7 +119,7 @@ static void Main(string[] args) ...@@ -119,7 +119,7 @@ static void Main(string[] args)
[WpfFact] [WpfFact]
[WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")] [WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")]
[Trait(Traits.Feature, Traits.Features.Formatting)] [Trait(Traits.Feature, Traits.Features.Formatting)]
public void FormatUsingStatementOnReturn() public void DoNotFormatUsingStatementOnReturn()
{ {
var code = @"class Program var code = @"class Program
{ {
...@@ -136,7 +136,7 @@ static void Main(string[] args) ...@@ -136,7 +136,7 @@ static void Main(string[] args)
static void Main(string[] args) static void Main(string[] args)
{ {
using (null) using (null)
using (null)$$ using (null)$$
} }
} }
"; ";
...@@ -144,6 +144,34 @@ static void Main(string[] args) ...@@ -144,6 +144,34 @@ static void Main(string[] args)
AssertFormatWithPasteOrReturn(expected, code, allowDocumentChanges: true, isPaste: false); AssertFormatWithPasteOrReturn(expected, code, allowDocumentChanges: true, isPaste: false);
} }
[WpfFact]
[WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")]
[Trait(Traits.Feature, Traits.Features.Formatting)]
public void FormatUsingStatementWhenTypingCloseParen()
{
var code = @"class Program
{
static void Main(string[] args)
{
using (null)
using (null)$$
}
}
";
var expected = @"class Program
{
static void Main(string[] args)
{
using (null)
using (null)
}
}
";
AssertFormatAfterTypeChar(code, expected);
}
[WpfFact] [WpfFact]
[WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")] [WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")]
[Trait(Traits.Feature, Traits.Features.Formatting)] [Trait(Traits.Feature, Traits.Features.Formatting)]
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
''' <summary>
''' Tests that want to exercise as much of the real command handling stack as possible.
''' </summary>
<[UseExportProvider]>
Public Class FormattingCommandHandlerTests
Public Shared ReadOnly Property AllCompletionImplementations() As IEnumerable(Of Object()) =
TestStateFactory.GetAllCompletionImplementations()
<WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")>
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Formatting)>
Public Sub TypingUsingStatementsProperlyAligns1(completionImplementation As CompletionImplementation)
Using state = TestStateFactory.CreateCSharpTestState(completionImplementation,
<Document>
using System;
class TestClass
{
void TestMethod(IDisposable obj)
{
$$
}
}
</Document>, includeFormatCommandHandler:=True)
state.SendTypeChars("using (obj)")
state.SendReturn()
' we should be indented one level from the using
AssertVirtualCaretColumn(state, 12)
' We should continue being indentded one level in
state.SendTypeChars("u")
Assert.Equal(" u", state.GetLineTextFromCaretPosition())
' Until close paren is typed. Then, we should align the usings
state.SendTypeChars("sing (obj")
Assert.Equal(" using (obj", state.GetLineTextFromCaretPosition())
state.SendTypeChars(")")
Assert.Equal(" using (obj)", state.GetLineTextFromCaretPosition())
state.SendReturn()
' we should be indented one level from the using
AssertVirtualCaretColumn(state, 12)
' typing open brace should align with using.
state.SendTypeChars("{")
Assert.Equal(" {", state.GetLineTextFromCaretPosition())
state.SendReturn()
' we should be indented one level from the {
AssertVirtualCaretColumn(state, 12)
' typing close brace should align with open brace.
state.SendTypeChars("}")
Assert.Equal(" }", state.GetLineTextFromCaretPosition())
End Using
End Sub
Private Shared Sub AssertVirtualCaretColumn(state As TestStateBase, expectedCol As Integer)
Dim caretLine = state.GetLineFromCurrentCaretPosition()
Dim caret = state.GetCaretPoint()
Assert.Equal(expectedCol, caret.VirtualBufferPosition.VirtualSpaces)
End Sub
End Class
End Namespace
...@@ -636,7 +636,12 @@ class Variable ...@@ -636,7 +636,12 @@ class Variable
state.SendTypeChars("a") state.SendTypeChars("a")
Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True) Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True)
state.SendReturn() state.SendReturn()
Assert.Contains("(var a, var a", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal)
Dim caretLine = state.GetLineFromCurrentCaretPosition()
Assert.Contains(" )", caretLine.GetText(), StringComparison.Ordinal)
Dim previousLine = caretLine.Snapshot.Lines(caretLine.LineNumber - 1)
Assert.Contains("(var a, var a", previousLine.GetText(), StringComparison.Ordinal)
End Using End Using
End Function End Function
...@@ -698,7 +703,12 @@ class Variable ...@@ -698,7 +703,12 @@ class Variable
state.SendReturn() state.SendReturn()
Await state.AssertNoCompletionSession() Await state.AssertNoCompletionSession()
Assert.Contains("(var as, var a", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal)
Dim caretLine = state.GetLineFromCurrentCaretPosition()
Assert.Contains(" )", caretLine.GetText(), StringComparison.Ordinal)
Dim previousLine = caretLine.Snapshot.Lines(caretLine.LineNumber - 1)
Assert.Contains("(var as, var a", previousLine.GetText(), StringComparison.Ordinal)
End Using End Using
End Function End Function
......
...@@ -273,8 +273,8 @@ public ITextSnapshotLine GetLineFromCurrentCaretPosition() ...@@ -273,8 +273,8 @@ public ITextSnapshotLine GetLineFromCurrentCaretPosition()
public string GetLineTextFromCaretPosition() public string GetLineTextFromCaretPosition()
{ {
var caretPosition = Workspace.Documents.Single(d => d.CursorPosition.HasValue).CursorPosition.Value; var caretPosition = GetCaretPoint();
return SubjectBuffer.CurrentSnapshot.GetLineFromPosition(caretPosition).GetText(); return caretPosition.BufferPosition.GetContainingLine().GetText();
} }
public (string TextBeforeCaret, string TextAfterCaret) GetLineTextAroundCaretPosition() public (string TextBeforeCaret, string TextAfterCaret) GetLineTextAroundCaretPosition()
......
...@@ -5797,6 +5797,74 @@ void M() ...@@ -5797,6 +5797,74 @@ void M()
await AssertFormatAsync(expected, code); await AssertFormatAsync(expected, code);
} }
[Fact]
[WorkItem(530580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")]
[Trait(Traits.Feature, Traits.Features.Formatting)]
public async Task NoIndentForNestedUsingWithoutBraces2()
{
var code = @"class C
{
void M()
{
using (null)
using (null)
using (null)
{
}
}
}
";
var expected = @"class C
{
void M()
{
using (null)
using (null)
using (null)
{
}
}
}
";
await AssertFormatAsync(expected, code);
}
[Fact]
[WorkItem(530580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530580")]
[Trait(Traits.Feature, Traits.Features.Formatting)]
public async Task NoIndentForNestedUsingWithoutBraces3()
{
var code = @"class C
{
void M()
{
using (null)
using (null)
using (null)
{
}
}
}
";
var expected = @"class C
{
void M()
{
using (null)
using (null)
using (null)
{
}
}
}
";
await AssertFormatAsync(expected, code);
}
[Fact] [Fact]
[WorkItem(546678, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546678")] [WorkItem(546678, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546678")]
[Trait(Traits.Feature, Traits.Features.Formatting)] [Trait(Traits.Feature, Traits.Features.Formatting)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册