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

Merge pull request #31111 from CyrusNajmabadi/blankLineIndentation

Use the new IBlankLineIndentationService in the string-splitting feature.
......@@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using static Microsoft.CodeAnalysis.Formatting.FormattingOptions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral
{
......@@ -17,8 +18,9 @@ private class InterpolatedStringSplitter : StringSplitter
Document document, int position,
SyntaxNode root, SourceText sourceText,
InterpolatedStringExpressionSyntax interpolatedStringExpression,
bool useTabs, int tabSize, CancellationToken cancellationToken)
: base(document, position, root, sourceText, useTabs, tabSize, cancellationToken)
bool useTabs, int tabSize, IndentStyle indentStyle,
CancellationToken cancellationToken)
: base(document, position, root, sourceText, useTabs, tabSize, indentStyle, cancellationToken)
{
_interpolatedStringExpression = interpolatedStringExpression;
}
......@@ -71,7 +73,7 @@ protected override BinaryExpressionSyntax CreateSplitString()
return SyntaxFactory.BinaryExpression(
SyntaxKind.AddExpression,
leftExpression,
GetPlusToken(),
PlusNewLineToken,
rightExpression.WithAdditionalAnnotations(RightNodeAnnotation));
}
......
......@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using static Microsoft.CodeAnalysis.Formatting.FormattingOptions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral
{
......@@ -12,8 +13,11 @@ private class SimpleStringSplitter : StringSplitter
private const char QuoteCharacter = '"';
private readonly SyntaxToken _token;
public SimpleStringSplitter(Document document, int position, SyntaxNode root, SourceText sourceText, SyntaxToken token, bool useTabs, int tabSize, CancellationToken cancellationToken)
: base(document, position, root, sourceText, useTabs, tabSize, cancellationToken)
public SimpleStringSplitter(
Document document, int position,
SyntaxNode root, SourceText sourceText, SyntaxToken token,
bool useTabs, int tabSize, IndentStyle indentStyle, CancellationToken cancellationToken)
: base(document, position, root, sourceText, useTabs, tabSize, indentStyle, cancellationToken)
{
_token = token;
}
......@@ -50,7 +54,7 @@ protected override BinaryExpressionSyntax CreateSplitString()
return SyntaxFactory.BinaryExpression(
SyntaxKind.AddExpression,
leftExpression,
GetPlusToken(),
PlusNewLineToken,
rightExpression.WithAdditionalAnnotations(RightNodeAnnotation));
}
......
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using static Microsoft.CodeAnalysis.Formatting.FormattingOptions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral
{
......@@ -15,6 +16,11 @@ private abstract class StringSplitter
{
protected static readonly SyntaxAnnotation RightNodeAnnotation = new SyntaxAnnotation();
protected static readonly SyntaxToken PlusNewLineToken = SyntaxFactory.Token(
leading: default,
SyntaxKind.PlusToken,
SyntaxFactory.TriviaList(SyntaxFactory.ElasticCarriageReturnLineFeed));
protected readonly Document Document;
protected readonly int CursorPosition;
protected readonly SourceText SourceText;
......@@ -23,7 +29,13 @@ private abstract class StringSplitter
protected readonly bool UseTabs;
protected readonly CancellationToken CancellationToken;
public StringSplitter(Document document, int position, SyntaxNode root, SourceText sourceText, bool useTabs, int tabSize, CancellationToken cancellationToken)
private readonly IndentStyle _indentStyle;
public StringSplitter(
Document document, int position,
SyntaxNode root, SourceText sourceText,
bool useTabs, int tabSize,
IndentStyle indentStyle, CancellationToken cancellationToken)
{
Document = document;
CursorPosition = position;
......@@ -31,13 +43,15 @@ public StringSplitter(Document document, int position, SyntaxNode root, SourceTe
SourceText = sourceText;
UseTabs = useTabs;
TabSize = tabSize;
_indentStyle = indentStyle;
CancellationToken = cancellationToken;
}
public static StringSplitter Create(
Document document, int position,
SyntaxNode root, SourceText sourceText,
bool useTabs, int tabSize, CancellationToken cancellationToken)
bool useTabs, int tabSize, IndentStyle indentStyle,
CancellationToken cancellationToken)
{
var token = root.FindToken(position);
......@@ -46,7 +60,7 @@ public StringSplitter(Document document, int position, SyntaxNode root, SourceTe
return new SimpleStringSplitter(
document, position, root,
sourceText, token, useTabs, tabSize,
cancellationToken);
indentStyle, cancellationToken);
}
var interpolatedStringExpression = TryGetInterpolatedStringExpression(token, position);
......@@ -55,7 +69,7 @@ public StringSplitter(Document document, int position, SyntaxNode root, SourceTe
return new InterpolatedStringSplitter(
document, position, root,
sourceText, interpolatedStringExpression,
useTabs, tabSize, cancellationToken);
useTabs, tabSize, indentStyle, cancellationToken);
}
return null;
......@@ -103,19 +117,12 @@ private static bool IsInterpolationOpenBrace(SyntaxToken token, int position)
return null;
}
return TrySplitWorker();
return SplitWorker();
}
private int? TrySplitWorker()
private int SplitWorker()
{
var newDocumentAndCaretPosition = SplitString();
if (newDocumentAndCaretPosition == null)
{
return null;
}
var newDocument = newDocumentAndCaretPosition.Item1;
var finalCaretPosition = newDocumentAndCaretPosition.Item2;
var (newDocument, finalCaretPosition) = SplitString();
var workspace = Document.Project.Solution.Workspace;
workspace.TryApplyChanges(newDocument.Project.Solution);
......@@ -123,15 +130,7 @@ private static bool IsInterpolationOpenBrace(SyntaxToken token, int position)
return finalCaretPosition;
}
protected static SyntaxToken GetPlusToken()
{
return SyntaxFactory.Token(
default(SyntaxTriviaList),
SyntaxKind.PlusToken,
SyntaxFactory.TriviaList(SyntaxFactory.ElasticCarriageReturnLineFeed));
}
private Tuple<Document, int> SplitString()
private (Document document, int caretPosition) SplitString()
{
var splitString = CreateSplitString();
......@@ -140,37 +139,28 @@ protected static SyntaxToken GetPlusToken()
var rightExpression = newRoot.GetAnnotatedNodes(RightNodeAnnotation).Single();
var indentString = GetIndentString(newRoot);
if (indentString == null)
{
return null;
}
var newRightExpression = rightExpression.WithLeadingTrivia(SyntaxFactory.ElasticWhitespace(indentString));
var newRoot2 = newRoot.ReplaceNode(rightExpression, newRightExpression);
var newDocument2 = Document.WithSyntaxRoot(newRoot2);
return Tuple.Create(newDocument2, rightExpression.Span.Start + indentString.Length + StringOpenQuoteLength());
return (newDocument2, rightExpression.Span.Start + indentString.Length + StringOpenQuoteLength());
}
private string GetIndentString(SyntaxNode newRoot)
{
var newDocument = Document.WithSyntaxRoot(newRoot);
var indentationService = newDocument.GetLanguageService<ISynchronousIndentationService>();
var indentationService = (IBlankLineIndentationService)newDocument.GetLanguageService<ISynchronousIndentationService>();
var originalLineNumber = SourceText.Lines.GetLineFromPosition(CursorPosition).LineNumber;
var desiredIndentation = indentationService.GetDesiredIndentation(
newDocument, originalLineNumber + 1, CancellationToken);
if (desiredIndentation == null)
{
return null;
}
var desiredIndentation = indentationService.GetBlankLineIndentation(
newDocument, originalLineNumber + 1, _indentStyle, CancellationToken);
var newSourceText = newDocument.GetSyntaxRootSynchronously(CancellationToken).SyntaxTree.GetText(CancellationToken);
var baseLine = newSourceText.Lines.GetLineFromPosition(desiredIndentation.Value.BasePosition);
var baseOffsetInLine = desiredIndentation.Value.BasePosition - baseLine.Start;
var baseLine = newSourceText.Lines.GetLineFromPosition(desiredIndentation.BasePosition);
var baseOffsetInLine = desiredIndentation.BasePosition - baseLine.Start;
var indent = baseOffsetInLine + desiredIndentation.Value.Offset;
var indent = baseOffsetInLine + desiredIndentation.Offset;
var indentString = indent.CreateIndentationString(UseTabs, TabSize);
return indentString;
}
......
......@@ -79,8 +79,8 @@ private bool SplitString(ITextView textView, ITextBuffer subjectBuffer, Snapshot
if (document != null)
{
var options = document.GetOptionsAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
var enabled = options.GetOption(
SplitStringLiteralOptions.Enabled);
var enabled = options.GetOption(SplitStringLiteralOptions.Enabled);
var indentStyle = options.GetOption(FormattingOptions.SmartIndent, document.Project.Language);
if (enabled)
{
......@@ -132,11 +132,14 @@ private bool LineContainsQuote(ITextSnapshotLine line, int caretPosition)
{
var useTabs = options.GetOption(FormattingOptions.UseTabs);
var tabSize = options.GetOption(FormattingOptions.TabSize);
var indentStyle = options.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp);
var root = document.GetSyntaxRootSynchronously(cancellationToken);
var sourceText = root.SyntaxTree.GetText(cancellationToken);
var splitter = StringSplitter.Create(document, position, root, sourceText, useTabs, tabSize, cancellationToken);
var splitter = StringSplitter.Create(
document, position, root, sourceText,
useTabs, tabSize, indentStyle, cancellationToken);
if (splitter == null)
{
return null;
......
......@@ -14,6 +14,7 @@
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Test.Utilities;
using Xunit;
using static Microsoft.CodeAnalysis.Formatting.FormattingOptions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SplitStringLiteral
{
......@@ -27,10 +28,16 @@ public class SplitStringLiteralCommandHandlerTests
/// failure.
/// </summary>
private void TestWorker(
string inputMarkup, string expectedOutputMarkup, Action callback, bool verifyUndo = true)
string inputMarkup,
string expectedOutputMarkup,
Action callback,
bool verifyUndo = true,
IndentStyle indentStyle = IndentStyle.Smart)
{
using (var workspace = TestWorkspace.CreateCSharp(inputMarkup))
{
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle);
var document = workspace.Documents.Single();
var view = document.GetTextView();
......@@ -76,7 +83,9 @@ public class SplitStringLiteralCommandHandlerTests
/// this known test infrastructure issure. This bug does not represent a product
/// failure.
/// </summary>
private void TestHandled(string inputMarkup, string expectedOutputMarkup, bool verifyUndo = true)
private void TestHandled(
string inputMarkup, string expectedOutputMarkup,
bool verifyUndo = true, IndentStyle indentStyle = IndentStyle.Smart)
{
TestWorker(
inputMarkup, expectedOutputMarkup,
......@@ -84,7 +93,7 @@ private void TestHandled(string inputMarkup, string expectedOutputMarkup, bool v
{
Assert.True(false, "Should not reach here.");
},
verifyUndo);
verifyUndo, indentStyle);
}
private void TestNotHandled(string inputMarkup)
......@@ -280,6 +289,56 @@ void M()
verifyUndo: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestInEmptyString_BlockIndent()
{
// Do not verifyUndo because of https://github.com/dotnet/roslyn/issues/28033
// When that issue is fixed, we can reenable verifyUndo
TestHandled(
@"class C
{
void M()
{
var v = ""[||]"";
}
}",
@"class C
{
void M()
{
var v = """" +
""[||]"";
}
}",
verifyUndo: false,
IndentStyle.Block);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestInEmptyString_NoneIndent()
{
// Do not verifyUndo because of https://github.com/dotnet/roslyn/issues/28033
// When that issue is fixed, we can reenable verifyUndo
TestHandled(
@"class C
{
void M()
{
var v = ""[||]"";
}
}",
@"class C
{
void M()
{
var v = """" +
""[||]"";
}
}",
verifyUndo: false,
IndentStyle.None);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestInEmptyInterpolatedString()
{
......@@ -301,6 +360,48 @@ void M()
}");
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestInEmptyInterpolatedString_BlockIndent()
{
TestHandled(
@"class C
{
void M()
{
var v = $""[||]"";
}
}",
@"class C
{
void M()
{
var v = $"""" +
$""[||]"";
}
}", indentStyle: IndentStyle.Block);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestInEmptyInterpolatedString_NoneIndent()
{
TestHandled(
@"class C
{
void M()
{
var v = $""[||]"";
}
}",
@"class C
{
void M()
{
var v = $"""" +
$""[||]"";
}
}", indentStyle: IndentStyle.None);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)]
public void TestSimpleString1()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册