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

Merge pull request #33983 from CyrusNajmabadi/simplifyEnterHandling

Simplify handling of 'enter' in formatting.
......@@ -39,7 +39,7 @@ public CSharpEditorFormattingService()
public bool SupportsFormatDocument => true;
public bool SupportsFormatOnPaste => true;
public bool SupportsFormatSelection => true;
public bool SupportsFormatOnReturn => true;
public bool SupportsFormatOnReturn => false;
public bool SupportsFormattingOnTypedCharacter(Document document, char ch)
{
......@@ -125,53 +125,11 @@ private IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document
{
var workspace = document.Project.Solution.Workspace;
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)
{
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);
}
Task<IList<TextChange>> IEditorFormattingService.GetFormattingChangesOnReturnAsync(Document document, int caretPosition, CancellationToken cancellationToken)
=> SpecializedTasks.Default<IList<TextChange>>();
private static async Task<bool> TokenShouldNotFormatOnTypeCharAsync(
SyntaxToken token, CancellationToken cancellationToken)
......@@ -354,7 +312,7 @@ private ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnu
return changes;
}
private IEnumerable<AbstractFormattingRule> GetTypingRules(Document document, SyntaxToken tokenBeforeCaret)
private IEnumerable<AbstractFormattingRule> GetTypingRules(SyntaxToken tokenBeforeCaret)
{
// Typing introduces several challenges around formatting.
// 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
}
}
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)
{
// invalid token to be formatted
......
......@@ -119,7 +119,7 @@ static void Main(string[] args)
[WpfFact]
[WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")]
[Trait(Traits.Feature, Traits.Features.Formatting)]
public void FormatUsingStatementOnReturn()
public void DoNotFormatUsingStatementOnReturn()
{
var code = @"class Program
{
......@@ -144,6 +144,34 @@ static void Main(string[] args)
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]
[WorkItem(912965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/912965")]
[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
state.SendTypeChars("a")
Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True)
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 Function
......@@ -698,7 +703,12 @@ class Variable
state.SendReturn()
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 Function
......
......@@ -273,8 +273,8 @@ public ITextSnapshotLine GetLineFromCurrentCaretPosition()
public string GetLineTextFromCaretPosition()
{
var caretPosition = Workspace.Documents.Single(d => d.CursorPosition.HasValue).CursorPosition.Value;
return SubjectBuffer.CurrentSnapshot.GetLineFromPosition(caretPosition).GetText();
var caretPosition = GetCaretPoint();
return caretPosition.BufferPosition.GetContainingLine().GetText();
}
public (string TextBeforeCaret, string TextAfterCaret) GetLineTextAroundCaretPosition()
......
......@@ -5797,6 +5797,74 @@ void M()
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]
[WorkItem(546678, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546678")]
[Trait(Traits.Feature, Traits.Features.Formatting)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册