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

Merge pull request #38907 from sharwell/test-tabs-master

Fix smart indent with hard tabs (merge to master)
......@@ -96,11 +96,14 @@ private static void ApplyChanges(ITextBuffer buffer, IList<TextChange> changes)
string code,
int indentationLine,
char ch,
bool useTabs,
int? baseIndentation = null,
TextSpan span = default)
{
// create tree service
using var workspace = TestWorkspace.CreateCSharp(code);
workspace.Options = workspace.Options.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, useTabs);
if (baseIndentation.HasValue)
{
var factory = workspace.Services.GetService<IHostDependentFormattingRuleFactoryService>()
......
......@@ -1349,9 +1349,23 @@ void Main(object o)
char ch,
int indentationLine,
int? expectedIndentation)
{
await AssertIndentUsingSmartTokenFormatterAsync(code, ch, indentationLine, expectedIndentation, useTabs: false).ConfigureAwait(false);
await AssertIndentUsingSmartTokenFormatterAsync(code.Replace(" ", "\t"), ch, indentationLine, expectedIndentation, useTabs: true).ConfigureAwait(false);
}
private async Task AssertIndentUsingSmartTokenFormatterAsync(
string code,
char ch,
int indentationLine,
int? expectedIndentation,
bool useTabs)
{
// create tree service
using var workspace = TestWorkspace.CreateCSharp(code);
workspace.Options = workspace.Options.WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs);
var hostdoc = workspace.Documents.First();
var buffer = hostdoc.GetTextBuffer();
......@@ -1377,10 +1391,23 @@ void Main(object o)
int indentationLine,
int? expectedIndentation,
IndentStyle indentStyle = IndentStyle.Smart)
{
await AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(code, indentationLine, expectedIndentation, useTabs: false, indentStyle).ConfigureAwait(false);
await AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(code.Replace(" ", "\t"), indentationLine, expectedIndentation, useTabs: true, indentStyle).ConfigureAwait(false);
}
private async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(
string code,
int indentationLine,
int? expectedIndentation,
bool useTabs,
IndentStyle indentStyle)
{
// create tree service
using var workspace = TestWorkspace.CreateCSharp(code);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle);
workspace.Options = workspace.Options
.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle)
.WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs);
var hostdoc = workspace.Documents.First();
var buffer = hostdoc.GetTextBuffer();
var snapshot = buffer.CurrentSnapshot;
......
......@@ -2793,10 +2793,47 @@ public void Test()
expectedIndentation: 12);
}
[WorkItem(38819, "https://github.com/dotnet/roslyn/issues/38819")]
[WpfFact]
[Trait(Traits.Feature, Traits.Features.SmartIndent)]
public void IndentationOfReturnInFileWithTabs1()
{
var code = @"
public class Example
{
public void Test(object session)
{
if (session == null)
return;
}
}";
// Ensure the test code doesn't get switched to spaces
Assert.Contains("\t\tif (session == null)", code);
AssertSmartIndent(
code,
indentationLine: 6,
expectedIndentation: 12,
useTabs: true,
options: null,
indentStyle: IndentStyle.Smart);
}
private void AssertSmartIndentInProjection(
string markup, int expectedIndentation,
string markup,
int expectedIndentation,
CSharpParseOptions options = null,
IndentStyle indentStyle = IndentStyle.Smart)
{
AssertSmartIndentInProjection(markup, expectedIndentation, useTabs: false, options, indentStyle);
AssertSmartIndentInProjection(markup.Replace(" ", "\t"), expectedIndentation, useTabs: true, options, indentStyle);
}
private void AssertSmartIndentInProjection(
string markup,
int expectedIndentation,
bool useTabs,
CSharpParseOptions options,
IndentStyle indentStyle)
{
var optionsSet = options != null
? new[] { options }
......@@ -2806,7 +2843,8 @@ public void Test()
{
using var workspace = TestWorkspace.CreateCSharp(markup, parseOptions: option);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle)
.WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs);
var subjectDocument = workspace.Documents.Single();
var projectedDocument =
......@@ -2833,6 +2871,18 @@ public void Test()
int? expectedIndentation,
CSharpParseOptions options = null,
IndentStyle indentStyle = IndentStyle.Smart)
{
AssertSmartIndent(code, indentationLine, expectedIndentation, useTabs: false, options, indentStyle);
AssertSmartIndent(code.Replace(" ", "\t"), indentationLine, expectedIndentation, useTabs: true, options, indentStyle);
}
private void AssertSmartIndent(
string code,
int indentationLine,
int? expectedIndentation,
bool useTabs,
CSharpParseOptions options,
IndentStyle indentStyle)
{
var optionsSet = options != null
? new[] { options }
......@@ -2842,7 +2892,8 @@ public void Test()
{
using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle)
.WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs);
TestIndentation(workspace, indentationLine, expectedIndentation);
}
}
......@@ -2852,6 +2903,17 @@ public void Test()
int? expectedIndentation,
CSharpParseOptions options = null,
IndentStyle indentStyle = IndentStyle.Smart)
{
AssertSmartIndent(code, expectedIndentation, useTabs: false, options, indentStyle);
AssertSmartIndent(code.Replace(" ", "\t"), expectedIndentation, useTabs: true, options, indentStyle);
}
private void AssertSmartIndent(
string code,
int? expectedIndentation,
bool useTabs,
CSharpParseOptions options,
IndentStyle indentStyle)
{
var optionsSet = options != null
? new[] { options }
......@@ -2861,7 +2923,8 @@ public void Test()
{
using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option);
workspace.Options = workspace.Options.WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle);
workspace.Options = workspace.Options.WithChangedOption(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);
......
......@@ -3435,8 +3435,17 @@ static void Main(string[] args)
}
internal static void AutoFormatToken(string markup, string expected)
{
AutoFormatToken(markup, expected, useTabs: false);
AutoFormatToken(markup.Replace(" ", "\t"), expected.Replace(" ", "\t"), useTabs: true);
}
internal static void AutoFormatToken(string markup, string expected, bool useTabs)
{
using var workspace = TestWorkspace.CreateCSharp(markup);
workspace.Options = workspace.Options.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, useTabs);
var subjectDocument = workspace.Documents.Single();
var commandHandler = workspace.GetService<FormatCommandHandler>();
......@@ -3471,8 +3480,17 @@ private Task AutoFormatOnCloseBraceAsync(string codeWithMarker, string expected,
}
private async Task AutoFormatOnMarkerAsync(string initialMarkup, string expected, SyntaxKind tokenKind, SyntaxKind startTokenKind)
{
await AutoFormatOnMarkerAsync(initialMarkup, expected, useTabs: false, tokenKind, startTokenKind).ConfigureAwait(false);
await AutoFormatOnMarkerAsync(initialMarkup.Replace(" ", "\t"), expected.Replace(" ", "\t"), useTabs: true, tokenKind, startTokenKind).ConfigureAwait(false);
}
private async Task AutoFormatOnMarkerAsync(string initialMarkup, string expected, bool useTabs, SyntaxKind tokenKind, SyntaxKind startTokenKind)
{
using var workspace = TestWorkspace.CreateCSharp(initialMarkup);
workspace.Options = workspace.Options.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, useTabs);
var tuple = GetService(workspace);
var testDocument = workspace.Documents.Single();
var buffer = testDocument.GetTextBuffer();
......
......@@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
......@@ -445,7 +446,7 @@ void M()
[WorkItem(9216, "DevDiv_Projects/Roslyn")]
[Fact, Trait(Traits.Feature, Traits.Features.SmartTokenFormatting)]
public void CloseBraceWithBaseIndentation()
public async Task CloseBraceWithBaseIndentation()
{
var markup = @"
class C
......@@ -460,7 +461,7 @@ void M()
#line hidden|]
}
}";
AssertSmartTokenFormatterCloseBraceWithBaseIndentation(markup, baseIndentation: 7, expectedIndentation: 11);
await AssertSmartTokenFormatterCloseBraceWithBaseIndentation(markup, baseIndentation: 7, expectedIndentation: 11);
}
[WorkItem(766159, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/766159")]
......@@ -475,7 +476,11 @@ void M()
#
}
}";
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: '#');
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: '#', useTabs: false);
Assert.Equal(0, actualIndentation);
actualIndentation = await GetSmartTokenFormatterIndentationAsync(code.Replace(" ", "\t"), indentationLine: 5, ch: '#', useTabs: true);
Assert.Equal(0, actualIndentation);
}
......@@ -491,7 +496,11 @@ void M()
#region
}
}";
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: 'n');
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: 'n', useTabs: false);
Assert.Equal(8, actualIndentation);
actualIndentation = await GetSmartTokenFormatterIndentationAsync(code.Replace(" ", "\t"), indentationLine: 5, ch: 'n', useTabs: true);
Assert.Equal(8, actualIndentation);
}
......@@ -508,8 +517,11 @@ void M()
#endregion
}
}";
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: 'n');
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 5, ch: 'n', useTabs: false);
Assert.Equal(8, actualIndentation);
actualIndentation = await GetSmartTokenFormatterIndentationAsync(code.Replace(" ", "\t"), indentationLine: 5, ch: 'n', useTabs: true);
Assert.Equal(8, actualIndentation);
}
......@@ -530,8 +542,11 @@ static IEnumerable<int> Goo()
}
}
";
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 9, ch: 't');
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 9, ch: 't', useTabs: false);
Assert.Equal(15, actualIndentation);
actualIndentation = await GetSmartTokenFormatterIndentationAsync(code.Replace(" ", "\t"), indentationLine: 9, ch: 't', useTabs: true);
Assert.Equal(15, actualIndentation);
}
......@@ -552,12 +567,21 @@ static IEnumerable<int> Goo()
}
}
";
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 9, ch: 'e');
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine: 9, ch: 'e', useTabs: false);
Assert.Equal(15, actualIndentation);
actualIndentation = await GetSmartTokenFormatterIndentationAsync(code.Replace(" ", "\t"), indentationLine: 9, ch: 'e', useTabs: true);
Assert.Equal(15, actualIndentation);
}
private async Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string markup, int baseIndentation, int expectedIndentation)
{
await AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(markup, baseIndentation, expectedIndentation, useTabs: false).ConfigureAwait(false);
await AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(markup.Replace(" ", "\t"), baseIndentation, expectedIndentation, useTabs: true).ConfigureAwait(false);
}
private Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string markup, int baseIndentation, int expectedIndentation)
private Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string markup, int baseIndentation, int expectedIndentation, bool useTabs)
{
MarkupTestFile.GetPositionAndSpan(markup,
out var code, out var position, out TextSpan span);
......@@ -566,6 +590,7 @@ private Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string m
code,
SourceText.From(code).Lines.IndexOf(position),
expectedIndentation,
useTabs,
baseIndentation,
span);
}
......@@ -577,7 +602,19 @@ private Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string m
int? baseIndentation = null,
TextSpan span = default)
{
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine, '{', baseIndentation, span);
await AssertSmartTokenFormatterOpenBraceAsync(code, indentationLine, expectedSpace, useTabs: false, baseIndentation, span).ConfigureAwait(false);
await AssertSmartTokenFormatterOpenBraceAsync(code.Replace(" ", "\t"), indentationLine, expectedSpace, useTabs: true, baseIndentation, span).ConfigureAwait(false);
}
private async Task AssertSmartTokenFormatterOpenBraceAsync(
string code,
int indentationLine,
int expectedSpace,
bool useTabs,
int? baseIndentation,
TextSpan span)
{
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine, '{', useTabs, baseIndentation, span);
Assert.Equal(expectedSpace, actualIndentation);
}
......@@ -585,16 +622,35 @@ private Task AssertSmartTokenFormatterOpenBraceWithBaseIndentationAsync(string m
string expected,
string code,
int indentationLine)
{
await AssertSmartTokenFormatterOpenBraceAsync(expected, code, indentationLine, useTabs: false).ConfigureAwait(false);
await AssertSmartTokenFormatterOpenBraceAsync(expected.Replace(" ", "\t"), code.Replace(" ", "\t"), indentationLine, useTabs: true).ConfigureAwait(false);
}
private async Task AssertSmartTokenFormatterOpenBraceAsync(
string expected,
string code,
int indentationLine,
bool useTabs)
{
// create tree service
using var workspace = TestWorkspace.CreateCSharp(code);
workspace.Options = workspace.Options.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, useTabs);
var buffer = workspace.Documents.First().GetTextBuffer();
var actual = await TokenFormatAsync(workspace, buffer, indentationLine, '{');
Assert.Equal(expected, actual);
}
private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string markup, int baseIndentation, int expectedIndentation)
private async Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string markup, int baseIndentation, int expectedIndentation)
{
await AssertSmartTokenFormatterCloseBraceWithBaseIndentation(markup, baseIndentation, expectedIndentation, useTabs: false).ConfigureAwait(false);
await AssertSmartTokenFormatterCloseBraceWithBaseIndentation(markup.Replace(" ", "\t"), baseIndentation, expectedIndentation, useTabs: true).ConfigureAwait(false);
}
private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string markup, int baseIndentation, int expectedIndentation, bool useTabs)
{
MarkupTestFile.GetPositionAndSpan(markup,
out var code, out var position, out TextSpan span);
......@@ -603,6 +659,7 @@ private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string marku
code,
SourceText.From(code).Lines.IndexOf(position),
expectedIndentation,
useTabs,
baseIndentation,
span);
}
......@@ -614,7 +671,19 @@ private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string marku
int? baseIndentation = null,
TextSpan span = default)
{
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine, '}', baseIndentation, span);
await AssertSmartTokenFormatterCloseBraceAsync(code, indentationLine, expectedSpace, useTabs: false, baseIndentation, span).ConfigureAwait(false);
await AssertSmartTokenFormatterCloseBraceAsync(code.Replace(" ", "\t"), indentationLine, expectedSpace, useTabs: true, baseIndentation, span).ConfigureAwait(false);
}
private async Task AssertSmartTokenFormatterCloseBraceAsync(
string code,
int indentationLine,
int expectedSpace,
bool useTabs,
int? baseIndentation,
TextSpan span)
{
var actualIndentation = await GetSmartTokenFormatterIndentationAsync(code, indentationLine, '}', useTabs, baseIndentation, span);
Assert.Equal(expectedSpace, actualIndentation);
}
......@@ -623,7 +692,17 @@ private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string marku
int indentationLine,
int expectedSpace)
{
Assert.NotNull(await Record.ExceptionAsync(() => GetSmartTokenFormatterIndentationAsync(code, indentationLine, '{')));
await ExpectException_SmartTokenFormatterOpenBraceAsync(code, indentationLine, expectedSpace, useTabs: false).ConfigureAwait(false);
await ExpectException_SmartTokenFormatterOpenBraceAsync(code.Replace(" ", "\t"), indentationLine, expectedSpace, useTabs: true).ConfigureAwait(false);
}
private async Task ExpectException_SmartTokenFormatterOpenBraceAsync(
string code,
int indentationLine,
int expectedSpace,
bool useTabs)
{
Assert.NotNull(await Record.ExceptionAsync(() => GetSmartTokenFormatterIndentationAsync(code, indentationLine, '{', useTabs)));
}
private async Task ExpectException_SmartTokenFormatterCloseBraceAsync(
......@@ -631,7 +710,17 @@ private Task AssertSmartTokenFormatterCloseBraceWithBaseIndentation(string marku
int indentationLine,
int expectedSpace)
{
Assert.NotNull(await Record.ExceptionAsync(() => GetSmartTokenFormatterIndentationAsync(code, indentationLine, '}')));
await ExpectException_SmartTokenFormatterCloseBraceAsync(code, indentationLine, expectedSpace, useTabs: false).ConfigureAwait(false);
await ExpectException_SmartTokenFormatterCloseBraceAsync(code.Replace(" ", "\t"), indentationLine, expectedSpace, useTabs: true).ConfigureAwait(false);
}
private async Task ExpectException_SmartTokenFormatterCloseBraceAsync(
string code,
int indentationLine,
int expectedSpace,
bool useTabs)
{
Assert.NotNull(await Record.ExceptionAsync(() => GetSmartTokenFormatterIndentationAsync(code, indentationLine, '}', useTabs)));
}
}
}
......@@ -2582,7 +2582,6 @@ End Namespace
code,
indentationLine:=3,
expectedIndentation:=0,
expectedBlankLineIndentation:=0,
indentStyle:=FormattingOptions.IndentStyle.None)
End Sub
......@@ -2970,6 +2969,27 @@ End Class
expectedIndentation:=12)
End Sub
<WorkItem(38819, "https://github.com/dotnet/roslyn/issues/38819")>
<WpfFact>
<Trait(Traits.Feature, Traits.Features.SmartIndent)>
Public Sub IndentationOfReturnInFileWithTabs1()
dim code = "
public class Example
public sub Test(session as object)
if (session is nothing)
return
end sub
end class"
' Ensure the test code doesn't get switched to spaces
Assert.Contains(vbTab & vbTab & "if (session is nothing)", code)
AssertSmartIndent(
code,
indentationLine:=4,
expectedIndentation:=12,
useTabs:=True,
indentStyle:=FormattingOptions.IndentStyle.Smart)
End sub
Private Sub AssertSmartIndentIndentationInProjection(
markup As String,
expectedIndentation As Integer)
......@@ -2996,10 +3016,21 @@ End Class
Private Sub AssertSmartIndent(
code As String, indentationLine As Integer,
expectedIndentation As Integer?,
Optional expectedBlankLineIndentation As Integer? = Nothing,
Optional indentStyle As FormattingOptions.IndentStyle = FormattingOptions.IndentStyle.Smart)
AssertSmartIndent(code, indentationLine, expectedIndentation, useTabs:=False, indentStyle)
AssertSmartIndent(code.Replace(" ", vbTab), indentationLine, expectedIndentation, useTabs:=True, indentStyle)
End Sub
''' <param name="indentationLine">0-based. The line number in code to get indentation for.</param>
Private Sub AssertSmartIndent(
code As String, indentationLine As Integer,
expectedIndentation As Integer?,
useTabs As Boolean,
indentStyle As FormattingOptions.IndentStyle)
Using workspace = TestWorkspace.CreateVisualBasic(code)
workspace.Options = workspace.Options.WithChangedOption(FormattingOptions.SmartIndent, LanguageNames.VisualBasic, indentStyle)
workspace.Options = workspace.Options _
.WithChangedOption(FormattingOptions.SmartIndent, LanguageNames.VisualBasic, indentStyle) _
.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.VisualBasic, useTabs)
TestIndentation(workspace, indentationLine, expectedIndentation)
End Using
......
......@@ -126,12 +126,23 @@ public bool TryGetSmartTokenIndentation(out IndentationResult indentationResult)
if (LineToBeIndented.LineNumber < updatedSourceText.Lines.Count)
{
var updatedLine = updatedSourceText.Lines[LineToBeIndented.LineNumber];
var offset = updatedLine.GetFirstNonWhitespaceOffset();
if (offset != null)
var nonWhitespaceOffset = updatedLine.GetFirstNonWhitespaceOffset();
if (nonWhitespaceOffset != null)
{
indentationResult = new IndentationResult(
basePosition: LineToBeIndented.Start,
offset: offset.Value);
// 'nonWhitespaceOffset' is simply an int indicating how many
// *characters* of indentation to include. For example, an indentation
// string of \t\t\t would just count for nonWhitespaceOffset of '3' (one
// for each tab char).
//
// However, what we want is the true columnar offset for the line.
// That's what our caller (normally the editor) needs to determine where
// to actually put the caret and what whitespace needs to proceed it.
//
// This can be computed with GetColumnFromLineOffset which again looks
// at the contents of the line, but this time evaluates how \t characters
// should translate to column chars.
var offset = updatedLine.GetColumnFromLineOffset(nonWhitespaceOffset.Value, _tabSize);
indentationResult = new IndentationResult(basePosition: LineToBeIndented.Start, offset: offset);
return true;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册