提交 babf816c 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #14601 from CyrusNajmabadi/portFix3

Only format an open curly if it the first token on a line.
......@@ -138,10 +138,37 @@ private static bool TokenShouldNotFormatOnReturn(SyntaxToken token)
return !token.IsKind(SyntaxKind.CloseParenToken) || !token.Parent.IsKind(SyntaxKind.UsingStatement);
}
private static bool TokenShouldNotFormatOnTypeChar(SyntaxToken token)
private static async Task<bool> TokenShouldNotFormatOnTypeCharAsync(
SyntaxToken token, CancellationToken cancellationToken)
{
return (token.IsKind(SyntaxKind.CloseParenToken) && !token.Parent.IsKind(SyntaxKind.UsingStatement)) ||
(token.IsKind(SyntaxKind.ColonToken) && !(token.Parent.IsKind(SyntaxKind.LabeledStatement) || token.Parent is SwitchLabelSyntax));
// If the token is a ) we only want to format if it's the close paren
// of a using statement. That way if we have nested usings, the inner
// using will align with the outer one when the user types the close paren.
if (token.IsKind(SyntaxKind.CloseParenToken) && !token.Parent.IsKind(SyntaxKind.UsingStatement))
{
return true;
}
// If the token is a : we only want to format if it's a labeled statement
// or case. When the colon is typed we'll want ot immediately have those
// statements snap to their appropriate indentation level.
if (token.IsKind(SyntaxKind.ColonToken) && !(token.Parent.IsKind(SyntaxKind.LabeledStatement) || token.Parent is SwitchLabelSyntax))
{
return true;
}
// Only format an { if it is the first token on a line. We don't want to
// mess with it if it's inside a line.
if (token.IsKind(SyntaxKind.OpenBraceToken))
{
var text = await token.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
if (!token.IsFirstTokenOnLine(text))
{
return true;
}
}
return false;
}
public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document, char typedChar, int caretPosition, CancellationToken cancellationToken)
......@@ -149,7 +176,7 @@ public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document
var formattingRules = this.GetFormattingRules(document, caretPosition);
// first, find the token user just typed.
SyntaxToken token = await GetTokenBeforeTheCaretAsync(document, caretPosition, cancellationToken).ConfigureAwait(false);
var token = await GetTokenBeforeTheCaretAsync(document, caretPosition, cancellationToken).ConfigureAwait(false);
if (token.IsMissing ||
!ValidSingleOrMultiCharactersTokenKind(typedChar, token.Kind()) ||
......@@ -164,10 +191,8 @@ public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document
return null;
}
// Check to see if any of the below. If not, bail.
// case 1: The token is ')' and the parent is an using statement.
// case 2: The token is ':' and the parent is either labelled statement or case switch or default switch
if (TokenShouldNotFormatOnTypeChar(token))
var shouldNotFormat = await TokenShouldNotFormatOnTypeCharAsync(token, cancellationToken).ConfigureAwait(false);
if (shouldNotFormat)
{
return null;
}
......
......@@ -68,7 +68,8 @@ private bool CloseBraceOfTryOrDoBlock(SyntaxToken endToken)
(endToken.Parent.IsParentKind(SyntaxKind.TryStatement) || endToken.Parent.IsParentKind(SyntaxKind.DoStatement));
}
public Task<IList<TextChange>> FormatTokenAsync(Workspace workspace, SyntaxToken token, CancellationToken cancellationToken)
public async Task<IList<TextChange>> FormatTokenAsync(
Workspace workspace, SyntaxToken token, CancellationToken cancellationToken)
{
Contract.ThrowIfTrue(token.Kind() == SyntaxKind.None || token.Kind() == SyntaxKind.EndOfFileToken);
......@@ -77,7 +78,7 @@ public Task<IList<TextChange>> FormatTokenAsync(Workspace workspace, SyntaxToken
if (previousToken.Kind() == SyntaxKind.None)
{
// no previous token. nothing to format
return Task.FromResult(SpecializedCollections.EmptyList<TextChange>());
return SpecializedCollections.EmptyList<TextChange>();
}
// This is a heuristic to prevent brace completion from breaking user expectation/muscle memory in common scenarios (see Devdiv:823958).
......@@ -100,12 +101,19 @@ public Task<IList<TextChange>> FormatTokenAsync(Workspace workspace, SyntaxToken
var smartTokenformattingRules = (new SmartTokenFormattingRule()).Concat(_formattingRules);
var adjustedStartPosition = previousToken.SpanStart;
var indentStyle = _optionSet.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp);
if (token.IsKind(SyntaxKind.OpenBraceToken) && token.IsFirstTokenOnLine(token.SyntaxTree.GetText()) && indentStyle != FormattingOptions.IndentStyle.Smart)
if (token.IsKind(SyntaxKind.OpenBraceToken) &&
indentStyle != FormattingOptions.IndentStyle.Smart)
{
adjustedStartPosition = token.SpanStart;
var text = await token.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
if (token.IsFirstTokenOnLine(text))
{
adjustedStartPosition = token.SpanStart;
}
}
return Formatter.GetFormattedTextChangesAsync(_root, new TextSpan[] { TextSpan.FromBounds(adjustedStartPosition, adjustedEndPosition) }, workspace, _optionSet, smartTokenformattingRules, cancellationToken);
return await Formatter.GetFormattedTextChangesAsync(_root,
new TextSpan[] { TextSpan.FromBounds(adjustedStartPosition, adjustedEndPosition) },
workspace, _optionSet, smartTokenformattingRules, cancellationToken).ConfigureAwait(false);
}
private class NoLineChangeFormattingRule : AbstractFormattingRule
......
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.Commands;
using Microsoft.CodeAnalysis.Editor.Implementation.Formatting;
using Microsoft.CodeAnalysis.Editor.Options;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
......@@ -162,7 +163,7 @@ static void Main(string[] args)
[WorkItem(977133, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/977133")]
[WpfFact, Trait(Traits.Feature, Traits.Features.Formatting)]
public async Task DoNotFormatRangeButFormatTokenOnOpenBrace()
public async Task DoNotFormatRangeOrFormatTokenOnOpenBraceOnSameLine()
{
var code = @"class C
{
......@@ -175,7 +176,30 @@ public void M()
{
public void M()
{
if (true) {
if (true) {
}
}";
await AssertFormatAfterTypeCharAsync(code, expected);
}
[WorkItem(14491, "https://github.com/dotnet/roslyn/pull/14491")]
[WpfFact, Trait(Traits.Feature, Traits.Features.Formatting)]
public async Task DoNotFormatRangeButFormatTokenOnOpenBraceOnNextLine()
{
var code = @"class C
{
public void M()
{
if (true)
{$$
}
}";
var expected = @"class C
{
public void M()
{
if (true)
{
}
}";
await AssertFormatAfterTypeCharAsync(code, expected);
......@@ -1142,6 +1166,64 @@ class C
await AssertFormatAfterTypeCharAsync(code, expected, optionSet);
}
[WpfFact, WorkItem(4435, "https://github.com/dotnet/roslyn/issues/4435")]
[Trait(Traits.Feature, Traits.Features.SmartTokenFormatting)]
public async Task OpenCurlyNotFormattedIfNotAtStartOfLine()
{
var code =
@"
class C
{
public int P {$$
}
";
var expected =
@"
class C
{
public int P {
}
";
var optionSet = new Dictionary<OptionKey, object>
{
{ new OptionKey(BraceCompletionOptions.EnableBraceCompletion, LanguageNames.CSharp), false }
};
await AssertFormatAfterTypeCharAsync(code, expected);
}
[WpfFact, WorkItem(4435, "https://github.com/dotnet/roslyn/issues/4435")]
[Trait(Traits.Feature, Traits.Features.SmartTokenFormatting)]
public async Task OpenCurlyFormattedIfAtStartOfLine()
{
var code =
@"
class C
{
public int P
{$$
}
";
var expected =
@"
class C
{
public int P
{
}
";
var optionSet = new Dictionary<OptionKey, object>
{
{ new OptionKey(BraceCompletionOptions.EnableBraceCompletion, LanguageNames.CSharp), false }
};
await AssertFormatAfterTypeCharAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.Formatting)]
public async Task DoNotFormatIncompleteBlockOnSingleLineIfNotTypingCloseCurly1()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册