diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs b/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs index 28d709117a03e4a91e9b62731af492fa18f2d7ef..12ec92cb5d7943aab82d54232d664d082f7437f2 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.Designer.cs @@ -60,6 +60,15 @@ internal class CSharpEditorResources { } } + /// + /// Looks up a localized string similar to Fix interpolated verbatim string. + /// + internal static string Fix_interpolated_verbatim_string { + get { + return ResourceManager.GetString("Fix_interpolated_verbatim_string", resourceCulture); + } + } + /// /// Looks up a localized string similar to (Press TAB to insert). /// diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx index d27291f3f75f3713e2799484bb52d9367fc888d4..e8650f88e00c1f7ba011edc03863931d5367645c 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Fix interpolated verbatim string + (Press TAB to insert) diff --git a/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..653220727825e774f0d64fd5ceea6f11ae12ecd2 --- /dev/null +++ b/src/EditorFeatures/CSharp/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandler.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Utilities; +using VSCommanding = Microsoft.VisualStudio.Commanding; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.FixInterpolatedVerbatimString +{ + /// + /// Replaces @$" with $@", which is the preferred and until C# 8.0 the only supported form + /// of an interpolated verbatim string start token. In C# 8.0 we still auto-correct to this form for consistency. + /// + [Export(typeof(VSCommanding.ICommandHandler))] + [ContentType(ContentTypeNames.CSharpContentType)] + [Name(nameof(FixInterpolatedVerbatimStringCommandHandler))] + internal sealed class FixInterpolatedVerbatimStringCommandHandler : IChainedCommandHandler + { + public string DisplayName => CSharpEditorResources.Fix_interpolated_verbatim_string; + + public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) + { + // We need to check for the token *after* the opening quote is typed, so defer to the editor first + nextCommandHandler(); + + if (args.TypedChar == '"') + { + var caret = args.TextView.GetCaretPoint(args.SubjectBuffer); + if (caret != null) + { + var position = caret.Value.Position; + var snapshot = caret.Value.Snapshot; + + if (position >= 3 && + snapshot[position - 1] == '"' && + snapshot[position - 2] == '$' && + snapshot[position - 3] == '@') + { + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document != null) + { + var root = document.GetSyntaxRootSynchronously(executionContext.OperationContext.UserCancellationToken); + var token = root.FindToken(position - 3); + if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken)) + { + args.SubjectBuffer.Replace(new Span(position - 3, 2), "$@"); + } + } + } + } + } + } + + public VSCommanding.CommandState GetCommandState(TypeCharCommandArgs args, Func nextCommandHandler) + => nextCommandHandler(); + } +} diff --git a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs index c31092dba7431ec0490400da9d5f30c11f9fcbe0..3af3564a9dab66366fec3eebe9ffeb2b588fa542 100644 --- a/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs +++ b/src/EditorFeatures/CSharp/SplitStringLiteral/SplitStringLiteralCommandHandler.cs @@ -1,4 +1,6 @@ -using System.ComponentModel.Composition; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.ComponentModel.Composition; using System.Threading; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf index a17aebf9f66c4fb7bdee6a4e2ad8048ec0803567..3391d2c1f867c972787cec3e8849b1927502ff41 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Pro vložení stiskněte TAB.) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf index 50d22d4cbf64fdc52f851364f371d28dfaa1a2f0..a66e264a4e40b28faf4dbcc87f02b43956bad397 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Zum Einfügen TAB-TASTE drücken) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf index c3a1bcdb8c24542f338aabf24a316dc2f17ad8d4..5bfe2078450de5d7139a38b0528338febd327bf2 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Presione TAB para insertar) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf index 371e6847a165012aa529c4bad1b361661f30ca2a..760cd1f717c28dbbda5828eff591a349fae8630a 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Appuyez sur TAB pour insérer) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf index 3f705fc00cd62b32051f2bb6f685e6ac7024ae47..70a6be74b8402cd857959af413fb2ede12235819 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Premere TAB per inserire) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf index 79836dd659f25b80d240893aaf58bbea87186f21..4e941b8e6e616766f785c845cb3355448495523a 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Tab キーを押して挿入) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf index 4f37904a65657456eb26d6a86927e95469d4722e..34d816961e3a5912f86286b79c5540086660b20b 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (삽입하려면 <Tab> 키 누름) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf index 8357da8a9bcb6ef4759c43218a321942963eb412..00308e0a7fa2b8a6aa68746599983110dae6bae0 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Naciśnij klawisz TAB, aby wstawić) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf index 62ccf9cbe2aa7d9715b4bde5148a0fd570c6cb90..110f9897ee18d76d36a0c19ff73a6ed5be0b1e2f 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Pressione TAB para inserir) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf index c863054ae86173e48f889375d6366f8861ae07d8..cb77ad446dd9bd6b0f76feb689d48934f012d034 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Нажмите клавишу TAB для вставки) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf index 68e2ef9108775b52a9289caca8b7254afeb09f7c..348464115430bf685941cce35fb2a0e2d19573c7 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (Eklemek için TAB tuşuna basın) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf index eebbc0d6aa1419520d46e612fad37ff8f69984c4..6c8ff00750991e7f9ef8c5b16aa26ce28db91372 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (按 Tab 插入) diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf index dca16e32a211a90a55a1deccaa0ffe269841613e..4bf9b233bf8602f3d6a8ef46bd41588ef0c58dae 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf @@ -2,6 +2,11 @@ + + Fix interpolated verbatim string + Fix interpolated verbatim string + + (Press TAB to insert) (按 TAB 鍵插入) diff --git a/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..5ce65c0be709a8812cefaae3cdaabc1988ab0a03 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/FixInterpolatedVerbatimString/FixInterpolatedVerbatimStringCommandHandlerTests.cs @@ -0,0 +1,315 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.Editor.CSharp.FixInterpolatedVerbatimString; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Text.Operations; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.FixInterpolatedVerbatimString +{ + [UseExportProvider] + public class FixInterpolatedVerbatimStringCommandHandlerTests + { + private static TestWorkspace CreateTestWorkspace(string inputMarkup) + { + var workspace = TestWorkspace.CreateCSharp(inputMarkup); + var document = workspace.Documents.Single(); + var view = document.GetTextView(); + view.SetSelection(document.SelectedSpans.Single().ToSnapshotSpan(view.TextBuffer.CurrentSnapshot)); + return workspace; + } + + private static (string quoteCharSnapshotText, int quoteCharCaretPosition) TypeQuoteChar(TestWorkspace workspace) + { + var view = workspace.Documents.Single().GetTextView(); + var commandHandler = new FixInterpolatedVerbatimStringCommandHandler(); + + string quoteCharSnapshotText = default; + int quoteCharCaretPosition = default; + + commandHandler.ExecuteCommand(new TypeCharCommandArgs(view, view.TextBuffer, '"'), + () => + { + var editorOperations = workspace.GetService().GetEditorOperations(view); + editorOperations.InsertText("\""); + + quoteCharSnapshotText = view.TextBuffer.CurrentSnapshot.GetText(); + quoteCharCaretPosition = view.Caret.Position.BufferPosition.Position; + + }, TestCommandExecutionContext.Create()); + + return (quoteCharSnapshotText, quoteCharCaretPosition); + } + + private static void TestHandled(string inputMarkup, string expectedOutputMarkup) + { + using (var workspace = CreateTestWorkspace(inputMarkup)) + { + var (quoteCharSnapshotText, quoteCharCaretPosition) = TypeQuoteChar(workspace); + var view = workspace.Documents.Single().GetTextView(); + + MarkupTestFile.GetSpans(expectedOutputMarkup, + out var expectedOutput, out ImmutableArray expectedSpans); + + Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.GetText()); + Assert.Equal(expectedSpans.Single().Start, view.Caret.Position.BufferPosition.Position); + + var history = workspace.GetService().GetHistory(view.TextBuffer); + history.Undo(count: 1); + + // Ensure that after undo, the ordering fix is undone but the quote remains inserted + Assert.Equal(quoteCharSnapshotText, view.TextBuffer.CurrentSnapshot.GetText()); + Assert.Equal(quoteCharCaretPosition, view.Caret.Position.BufferPosition.Position); + } + } + + private static void TestNotHandled(string inputMarkup) + { + using (var workspace = CreateTestWorkspace(inputMarkup)) + { + var originalView = workspace.Documents.Single().GetTextView(); + var originalSnapshotText = originalView.TextBuffer.CurrentSnapshot.GetText(); + var originalCaretPosition = originalView.Caret.Position.BufferPosition.Position; + + var (quoteCharSnapshotText, quoteCharCaretPosition) = TypeQuoteChar(workspace); + var view = workspace.Documents.Single().GetTextView(); + + Assert.Equal(quoteCharSnapshotText, view.TextBuffer.CurrentSnapshot.GetText()); + Assert.Equal(quoteCharCaretPosition, view.Caret.Position.BufferPosition.Position); + + var history = workspace.GetService().GetHistory(view.TextBuffer); + history.Undo(count: 1); + + // Ensure that after undo, the quote is removed because the command made no changes + Assert.Equal(originalSnapshotText, view.TextBuffer.CurrentSnapshot.GetText()); + Assert.Equal(originalCaretPosition, view.Caret.Position.BufferPosition.Position); + } + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestAfterAtSignDollarSign() + { + TestHandled( +@"class C +{ + void M() + { + var v = @$[||] + } +}", +@"class C +{ + void M() + { + var v = $@""[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingAfterDollarSignAtSign() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $@[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingAfterAtSign() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = @[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingAfterDollarSign() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInEmptyFileAfterAtSignDollarSign() + { + TestNotHandled(@"@$[||]"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInEmptyFileAfterDollarSign() + { + TestNotHandled(@"$[||]"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInEmptyFile() + { + TestNotHandled(@"[||]"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestAfterAtSignDollarSignEndOfFile() + { + TestHandled( +@"class C +{ + void M() + { + var v = @$[||]", +@"class C +{ + void M() + { + var v = $@""[||]"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInClassDeclaration() + { + TestNotHandled( +@"class C +{ + @$[||] +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInComment1() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = // @$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInComment2() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = /* @$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInString() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = ""@$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInVerbatimString() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = @""@$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInInterpolatedString() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $""@$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInInterpolatedVerbatimString1() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $@""@$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestMissingInInterpolatedVerbatimString2() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = @$""@$[||] + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.FixInterpolatedVerbatimString)] + public void TestTrivia() + { + TestHandled( +@"class C +{ + void M() + { + var v = // a + /* b */ @$[||] // c + } +}", +@"class C +{ + void M() + { + var v = // a + /* b */ $@""[||] // c + } +}"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index 395c30f3e1a7c896c2679bec90e1015aa1057689..595aba796f67a7cb44a705c7615bbea7d4817d6b 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral; diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs index e2b458ae637711875616c98e066bfdc7bc6e1c56..605f809c4a042540943256b800773c648528b974 100644 --- a/src/Test/Utilities/Portable/Traits/Traits.cs +++ b/src/Test/Utilities/Portable/Traits/Traits.cs @@ -179,6 +179,7 @@ public static class Features public const string F1Help = nameof(F1Help); public const string FindReferences = nameof(FindReferences); public const string FixIncorrectTokens = nameof(FixIncorrectTokens); + public const string FixInterpolatedVerbatimString = nameof(FixInterpolatedVerbatimString); public const string Formatting = nameof(Formatting); public const string GoToDefinition = nameof(GoToDefinition); public const string GoToImplementation = nameof(GoToImplementation); diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs index f34f93d5e655469e470f4562c11e65e1b0b4ee86..634c1699ff7d8d8f2b4af3d43b5bfac7fc40c563 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs @@ -200,6 +200,38 @@ class C { VisualStudio.Editor.Verify.CurrentLineText("string str = \"Hi Roslyn!\"$$", assertCaretPosition: true); } + [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void DoubleQuote_FixedInterpolatedVerbatimString() + { + SetUpEditor(@" +class C +{ + void M() + { + $$ + } +}"); + + VisualStudio.Editor.SendKeys("var v = @$\""); + VisualStudio.Editor.Verify.CurrentLineText("var v = $@\"$$\"", assertCaretPosition: true); + + // Backspace removes quotes + VisualStudio.Editor.SendKeys(VirtualKey.Backspace); + VisualStudio.Editor.Verify.CurrentLineText("var v = $@$$", assertCaretPosition: true); + + // Undo puts them back + VisualStudio.Editor.Undo(); + VisualStudio.Editor.Verify.CurrentLineText("var v = $@\"$$\"", assertCaretPosition: true); + + // First, the FixInterpolatedVerbatimString action is undone (@$ reordering) + VisualStudio.Editor.Undo(); + VisualStudio.Editor.Verify.CurrentLineText("var v = @$\"$$\"", assertCaretPosition: true); + + // Then the automatic quote completion is undone + VisualStudio.Editor.Undo(); + VisualStudio.Editor.Verify.CurrentLineText("var v = @$\"$$", assertCaretPosition: true); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] public void AngleBracket_PossibleGenerics_InsertionAndCompletion() {