提交 2b8be03c 编写于 作者: A Andrew Hall (METAL)

Implement MoveToNamespace feature

Move to namespace allows a user to move all symbols in a context
to a different namespace, whether it's a new one or existing. This is
different from renaming a namespace as not all symbols in the namespace
are moved, only ones within the current document.

It relies on the IChangeNamespaceService implementation to do the heavy
lifting. Since the current implementation only supports C#, this new
feature will as well.

After this is checked in, when a user has the cursor inside a namespace
declaration that has no nested namespace declarations within it, a code
fix will be suggested to pop up a dialog and help the user choose a new
namespace.
上级 6490d61e
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MoveToNamespace
{
public class MoveToNamespaceTests : AbstractMoveToNamespaceTests
{
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_CaretOnNamespaceName()
{
var markup = @"
using System;
namespace A$$
{
class MyClass
{
void Method() { }
}
}";
var expectedMarkup = @"
using System;
namespace B
{
class MyClass
{
void Method() { }
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: true,
expectedNamespace: "B",
expectedMarkup: expectedMarkup);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_CaretOnNamespaceKeyword()
{
var markup = @"
using System;
namespace$$ A
{
class MyClass
{
void Method() { }
}
}";
var expectedMarkup = @"
using System;
namespace B
{
class MyClass
{
void Method() { }
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: true,
expectedNamespace: "B",
expectedMarkup: expectedMarkup);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_CaretOnNamespaceNameMultipleDeclarations()
{
var markup = @"
using System;
namespace A$$
{
class MyClass
{
void Method() { }
}
class MyOtherClass
{
void Method() { }
}
}";
var expectedMarkup = @"
using System;
namespace B
{
class MyClass
{
void Method() { }
}
class MyOtherClass
{
void Method() { }
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: true,
expectedNamespace: "B",
expectedMarkup: expectedMarkup);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_CaretOnTypeDeclaration()
{
var markup = @"
using System;
namespace A
{
class MyClass$$
{
void Method() {}
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_WithVariousSymbols()
{
var markup = @"
using System;
namespace A$$
{
public delegate void MyDelegate();
public enum MyEnum
{
One,
Two,
Three
}
public struct MyStruct
{ }
public interface MyInterface
{ }
class MyClass
{
void Method() { }
}
class MyOtherClass
{
void Method() { }
}
}";
var expectedMarkup = @"
using System;
namespace B
{
public delegate void MyDelegate();
public enum MyEnum
{
One,
Two,
Three
}
public struct MyStruct
{ }
public interface MyInterface
{ }
class MyClass
{
void Method() { }
}
class MyOtherClass
{
void Method() { }
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: true,
expectedNamespace: "B",
expectedMarkup: expectedMarkup);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
public async Task MoveToNamespace_NestedNamespace()
{
var markup = @"
using System;
namespace A$$
{
namespace C
{
class MyClass
{
void Method() { }
}
}
}";
await TestMoveToNamespaceCommandCSharpAsync(
markup,
expectedSuccess: false);
}
}
}
// 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.AddImports;
using Microsoft.CodeAnalysis.CSharp.ChangeNamespace;
using Microsoft.CodeAnalysis.CSharp.MoveToNamespace;
using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.Composition;
using Xunit;
using static Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.AbstractCodeActionOrUserDiagnosticTest;
namespace Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace
{
[UseExportProvider]
public abstract class AbstractMoveToNamespaceTests
{
private static readonly IExportProviderFactory CSharpExportProviderFactory =
ExportProviderCache.GetOrCreateExportProviderFactory(
TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic
.WithPart(typeof(TestMoveToNamespaceOptionsService))
.WithPart(typeof(CSharpMoveToNamespaceService))
.WithPart(typeof(CSharpChangeNamespaceService))
.WithPart(typeof(Experiments.DefaultExperimentationService))
.WithPart(typeof(CSharpAddImportsService))
.WithPart(typeof(CSharpRemoveUnnecessaryImportsService)));
public static Task TestMoveToNamespaceCommandCSharpAsync(
string markup,
bool expectedSuccess,
string expectedNamespace = null,
string expectedMarkup = null)
{
return TestMoveToNamespaceCommandAsync(
markup,
expectedSuccess,
LanguageNames.CSharp,
expectedNamespace: expectedNamespace,
expectedMarkup: expectedMarkup);
}
public static Task TestMoveToNamespaceCommandVisualBasicAsync(
string markup,
bool expectedSuccess,
string expectedNamespace = null,
string expectedMarkup = null)
{
return TestMoveToNamespaceCommandAsync(
markup,
expectedSuccess,
LanguageNames.VisualBasic,
expectedNamespace: expectedNamespace,
expectedMarkup: expectedMarkup);
}
public static async Task TestMoveToNamespaceCommandAsync(
string markup,
bool expectedSuccess,
string languageName,
string expectedNamespace = null,
string expectedMarkup = null,
CompilationOptions compilationOptions = null)
{
expectedNamespace = expectedNamespace ?? string.Empty;
var parameters = new TestParameters();
using (var workspace = CreateWorkspace(markup, languageName, compilationOptions, parameters))
{
var testDocument = workspace.Documents.Single(d => d.CursorPosition.HasValue);
var document = workspace.CurrentSolution.GetDocument(testDocument.Id);
var result = await MoveViaCommandAsync(testDocument, document, expectedNamespace);
if (expectedSuccess)
{
Assert.True(result.Succeeded);
Assert.NotNull(result.UpdatedSolution);
Assert.NotNull(result.UpdatedDocumentId);
if (expectedMarkup != null)
{
var updatedDocument = result.UpdatedSolution.GetDocument(result.UpdatedDocumentId);
var updatedText = await updatedDocument.GetTextAsync().ConfigureAwait(false);
Assert.Equal(expectedMarkup, updatedText.ToString());
}
}
else
{
Assert.False(result.Succeeded);
}
}
}
private static TestWorkspace CreateWorkspace(
string markup,
string languageName,
CompilationOptions compilationOptions,
TestParameters parameters)
{
var exportProviderFactory = GetExportProviderFactory(languageName);
var exportProvider = exportProviderFactory.CreateExportProvider();
var workspace = languageName == LanguageNames.CSharp
? TestWorkspace.CreateCSharp(markup, exportProvider: exportProvider, compilationOptions: compilationOptions as CSharpCompilationOptions)
: TestWorkspace.CreateVisualBasic(markup, exportProvider: exportProvider, compilationOptions: compilationOptions);
workspace.ApplyOptions(parameters.options);
return workspace;
}
private static IExportProviderFactory GetExportProviderFactory(string languageName)
{
return languageName == LanguageNames.CSharp
? CSharpExportProviderFactory
: throw new InvalidOperationException("VB is not currently supported");
}
private static async Task<MoveToNamespaceResult> MoveViaCommandAsync(
TestHostDocument testDocument,
Document document,
string newNamespace)
{
var cancellationToken = CancellationToken.None;
var moveToNamespaceService = document.GetLanguageService<AbstractMoveToNamespaceService>();
var analysisResult = await moveToNamespaceService.AnalyzeTypeAtPositionAsync(
document,
testDocument.CursorPosition.Value,
cancellationToken: cancellationToken).ConfigureAwait(false);
return await moveToNamespaceService.MoveToNamespaceAsync(
analysisResult,
newNamespace,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
extern alias WORKSPACES;
using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Notification;
using WORKSPACES::Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace
{
[Export(typeof(IMoveToNamespaceOptionsService))]
[PartNotDiscoverable]
class TestMoveToNamespaceOptionsService : IMoveToNamespaceOptionsService
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public TestMoveToNamespaceOptionsService()
{
}
public Task<MoveToNamespaceOptionsResult> GetChangeNamespaceOptionsAsync(ISyntaxFactsService syntaxFactsService, INotificationService notificationService, string defaultNamespace, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
}
// 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.Composition;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.MoveToNamespace;
namespace Microsoft.CodeAnalysis.CSharp.MoveToNamespace
{
[ExportLanguageService(typeof(AbstractMoveToNamespaceService), LanguageNames.CSharp), Shared]
internal class CSharpMoveToNamespaceService :
AbstractMoveToNamespaceService<CompilationUnitSyntax, NamespaceDeclarationSyntax>
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpMoveToNamespaceService(IMoveToNamespaceOptionsService moveToNamespaceOptionsService)
: base(moveToNamespaceOptionsService)
{
}
}
}
......@@ -28,6 +28,7 @@ internal static class PredefinedCodeRefactoringProviderNames
public const string MergeConsecutiveIfStatements = "Merge Consecutive If Statements Code Action Provider";
public const string MergeNestedIfStatements = "Merge Nested If Statements Code Action Provider";
public const string MoveDeclarationNearReference = "Move Declaration Near Reference Code Action Provider";
public const string MoveToNamespace = "Move To Namespace Code Action Provider";
public const string MoveTypeToFile = "Move Type To File Code Action Provider";
public const string PullMemberUp = "Pull Member Up Code Action Provider";
public const string ReplaceDocCommentTextWithTag = "Replace Documentation Comment Text With Tag Code Action Provider";
......
......@@ -2624,6 +2624,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Move to namespace....
/// </summary>
internal static string Move_to_namespace {
get {
return ResourceManager.GetString("Move_to_namespace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Move type to {0}.
/// </summary>
......
......@@ -1457,6 +1457,9 @@ This version used in: {2}</value>
<data name="Move_file_to_project_root_folder" xml:space="preserve">
<value>Move file to project root folder</value>
</data>
<data name="Move_to_namespace" xml:space="preserve">
<value>Move to namespace...</value>
</data>
<data name="Change_to_global_namespace" xml:space="preserve">
<value>Change to global namespace</value>
</data>
......
// 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.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ChangeNamespace;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
internal abstract class AbstractMoveToNamespaceService : ILanguageService
{
internal abstract Task<ImmutableArray<MoveToNamespaceCodeAction>> GetCodeActionsAsync(Document document, TextSpan span, CancellationToken cancellationToken);
internal abstract Task<MoveToNamespaceAnalysisResult> AnalyzeTypeAtPositionAsync(Document document, int position, CancellationToken cancellationToken);
public abstract Task<MoveToNamespaceResult> MoveToNamespaceAsync(MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, CancellationToken cancellationToken);
public abstract MoveToNamespaceOptionsResult GetOptions(Document document, string defaultNamespace, CancellationToken cancellationToken);
}
internal abstract class AbstractMoveToNamespaceService<TCompilationSyntax, TNamespaceDeclarationSyntax>
: AbstractMoveToNamespaceService
{
private IMoveToNamespaceOptionsService _moveToNamespaceOptionsService;
public AbstractMoveToNamespaceService(IMoveToNamespaceOptionsService moveToNamespaceOptionsService)
{
_moveToNamespaceOptionsService = moveToNamespaceOptionsService;
}
internal override async Task<ImmutableArray<MoveToNamespaceCodeAction>> GetCodeActionsAsync(
Document document,
TextSpan span,
CancellationToken cancellationToken)
{
var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, cancellationToken).ConfigureAwait(false);
return typeAnalysisResult.CanPerform
? ImmutableArray.Create(new MoveToNamespaceCodeAction(this, typeAnalysisResult))
: ImmutableArray<MoveToNamespaceCodeAction>.Empty;
}
internal override async Task<MoveToNamespaceAnalysisResult> AnalyzeTypeAtPositionAsync(
Document document,
int position,
CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync().ConfigureAwait(false);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(position);
var node = token.Parent;
var symbolInfo = semanticModel.GetSymbolInfo(node, cancellationToken: cancellationToken);
var symbol = symbolInfo.Symbol;
if (symbol is INamespaceSymbol namespaceSymbol)
{
node = node.FirstAncestorOrSelf<SyntaxNode>(a => a is TNamespaceDeclarationSyntax);
}
if (node is TNamespaceDeclarationSyntax declarationSyntax)
{
if (ContainsNamespaceDeclaration(node))
{
return new MoveToNamespaceAnalysisResult("Container contains nested namespace declaration");
}
return new MoveToNamespaceAnalysisResult(document, node, declarationSyntax.GetTypeDisplayName());
}
return new MoveToNamespaceAnalysisResult("Not a valid position");
}
private bool ContainsNamespaceDeclaration(SyntaxNode node)
=> node.DescendantNodes(n => n is TCompilationSyntax || n is TNamespaceDeclarationSyntax)
.OfType<TNamespaceDeclarationSyntax>().Any();
public override async Task<MoveToNamespaceResult> MoveToNamespaceAsync(
MoveToNamespaceAnalysisResult analysisResult,
string targetNamespace,
CancellationToken cancellationToken)
{
if (!analysisResult.CanPerform)
{
return MoveToNamespaceResult.Failed;
}
var changeNamespaceService = analysisResult.Document.GetLanguageService<IChangeNamespaceService>();
if (changeNamespaceService == null)
{
return MoveToNamespaceResult.Failed;
}
var changedSolution = await changeNamespaceService.ChangeNamespaceAsync(
analysisResult.Document,
analysisResult.Container,
targetNamespace,
cancellationToken).ConfigureAwait(false);
return new MoveToNamespaceResult(changedSolution, analysisResult.Document.Id);
}
public override MoveToNamespaceOptionsResult GetOptions(
Document document,
string defaultNamespace,
CancellationToken cancellationToken)
{
var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
var notificationService = document.Project.Solution.Workspace.Services.GetService<INotificationService>();
return _moveToNamespaceOptionsService.GetChangeNamespaceOptionsAsync(
syntaxFactsService,
notificationService,
defaultNamespace,
cancellationToken).WaitAndGetResult(cancellationToken);
}
}
}
// 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.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
internal interface IMoveToNamespaceOptionsService : IWorkspaceService
{
Task<MoveToNamespaceOptionsResult> GetChangeNamespaceOptionsAsync(
ISyntaxFactsService syntaxFactsService,
INotificationService notificationService,
string defaultNamespace,
CancellationToken cancellationToken);
}
}
// 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.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
internal class MoveToNamespaceAnalysisResult
{
public bool CanPerform { get; }
public Document Document { get; }
public string ErrorMessage { get; }
public SyntaxNode Container { get; }
public string OriginalNamespace { get; }
public MoveToNamespaceAnalysisResult(
Document document,
SyntaxNode container,
string originalNamespace)
{
CanPerform = true;
Document = document;
Container = container;
OriginalNamespace = originalNamespace;
}
public MoveToNamespaceAnalysisResult(string errorMessage)
{
CanPerform = false;
ErrorMessage = errorMessage;
}
}
}
// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
internal class MoveToNamespaceCodeAction : CodeActionWithOptions
{
private readonly AbstractMoveToNamespaceService _changeNamespaceService;
private readonly MoveToNamespaceAnalysisResult _moveToNamespaceAnalysisResult;
public override string Title => FeaturesResources.Move_to_namespace;
public MoveToNamespaceCodeAction(AbstractMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult)
{
_changeNamespaceService = changeNamespaceService;
_moveToNamespaceAnalysisResult = analysisResult;
}
public override object GetOptions(CancellationToken cancellationToken)
{
return _changeNamespaceService.GetOptions(
_moveToNamespaceAnalysisResult.Document,
_moveToNamespaceAnalysisResult.OriginalNamespace,
cancellationToken);
}
protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(object options, CancellationToken cancellationToken)
{
IEnumerable<CodeActionOperation> operations = null;
if (options is MoveToNamespaceOptionsResult moveToNamespaceOptions && !moveToNamespaceOptions.IsCancelled)
{
var moveToNamespaceResult = await _changeNamespaceService.MoveToNamespaceAsync(
_moveToNamespaceAnalysisResult,
moveToNamespaceOptions.Namespace,
cancellationToken).ConfigureAwait(false);
if (moveToNamespaceResult.Succeeded)
{
operations = new CodeActionOperation[]
{
new ApplyChangesOperation(moveToNamespaceResult.UpdatedSolution)
};
}
}
return operations;
}
}
}
// 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.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.MoveToNamespace), Shared]
internal class MoveToNamespaceCodeActionProvider : CodeRefactoringProvider
{
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var service = context.Document.GetLanguageService<AbstractMoveToNamespaceService>();
var actions = await service.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
context.RegisterRefactorings(actions);
}
}
}
// 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.Collections.Immutable;
namespace Microsoft.CodeAnalysis.MoveToNamespace
{
internal class MoveToNamespaceOptionsResult
{
public static readonly MoveToNamespaceOptionsResult Cancelled = new MoveToNamespaceOptionsResult(isCancelled: true);
public bool IsCancelled { get; }
public string Namespace { get; }
public MoveToNamespaceOptionsResult(bool isCancelled)
{
IsCancelled = true;
}
public MoveToNamespaceOptionsResult(string @namespace)
{
Namespace = @namespace;
}
}
}
// 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.MoveToNamespace
{
internal class MoveToNamespaceResult
{
public static MoveToNamespaceResult Failed = new MoveToNamespaceResult(succeeded: false);
public bool Succeeded { get; }
public Solution UpdatedSolution { get; }
public DocumentId UpdatedDocumentId { get; }
public MoveToNamespaceResult(Solution solution, DocumentId updatedDocumentId)
{
UpdatedSolution = solution;
UpdatedDocumentId = updatedDocumentId;
Succeeded = true;
}
private MoveToNamespaceResult(bool succeeded)
{
Succeeded = succeeded;
}
}
}
......@@ -212,6 +212,11 @@
<target state="translated">Přesunout soubor do kořenové složky projektu</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Soukromý člen {0} se může odebrat, jak jeho přiřazená hodnota se nikdy nečte.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Datei in den Stammordner des Projekts verschieben</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Der private Member "{0}" kann entfernt werden, da der zugewiesene Wert nie gelesen wird.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Mover el archivo a la carpeta raíz del proyecto</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Un miembro privado "{0}" puede retirarse porque el valor asignado a él no se lee nunca.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Déplacer le fichier dans le dossier racine du projet</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Vous pouvez supprimer le membre privé '{0}', car la valeur qui lui est attribuée n'est jamais lue.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Sposta il file nella cartella radice del progetto</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">È possibile rimuovere il membro privato '{0}' perché il valore assegnato ad esso non viene mai letto.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">ファイルをプロジェクト ルート フォルダーに移動します</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">割り当てられている値が読み取られることがないようにプライベートメンバー '{0}' を削除できます。</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">파일을 프로젝트 루트 폴더로 이동</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Private 멤버 '{0}'에 할당된 값을 읽을 수 없으므로 이 멤버를 제거할 수 있습니다.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Przenieś plik do folderu głównego projektu</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Prywatną składową „{0}” można usunąć, ponieważ przypisana do niej wartość nie jest nigdy odczytywana.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Mover o arquivo para a pasta raiz do projeto</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">O membro particular '{0}' pode ser removido pois o valor atribuído a ele nunca é lido.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Переместить файл в корневую папку проекта</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Закрытый член «{0}» может быть удален как значение, присвоенное него никогда не читал.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">Dosyayı proje kök klasörüne taşı</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">Kendisine atanmış değeri hiç okurken özel üye '{0}'-ebilmek var olmak çıkarmak.</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">将文件移动到项目根文件夹</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">可删除私有成员“{0}”,因为永不会读取分配给它的值。</target>
......
......@@ -212,6 +212,11 @@
<target state="translated">將檔案移到專案根資料夾</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move to namespace...</source>
<target state="new">Move to namespace...</target>
<note />
</trans-unit>
<trans-unit id="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Private member '{0}' can be removed as the value assigned to it is never read.</source>
<target state="translated">因為永遠不會讀取指派給私用成員 '{0}' 的值,所以可移除該成員。</target>
......
......@@ -215,6 +215,7 @@ public static class Features
public const string LinkedFileDiffMerging = nameof(LinkedFileDiffMerging);
public const string MetadataAsSource = nameof(MetadataAsSource);
public const string MSBuildWorkspace = nameof(MSBuildWorkspace);
public const string MoveToNamespace = nameof(MoveToNamespace);
public const string NamingStyle = nameof(NamingStyle);
public const string NavigableSymbols = nameof(NavigableSymbols);
public const string NavigateTo = nameof(NavigateTo);
......
<vs:DialogWindow x:Uid="MoveToNamespaceDialog"
x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace.MoveToNamespaceDialog"
x:ClassModifier="internal"
x:Name="dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0"
xmlns:u="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.Utilities"
mc:Ignorable="d"
d:DesignHeight="140" d:DesignWidth="460"
Height="140" Width="460"
MinHeight="140" MinWidth="460"
Title="{Binding ElementName=dialog, Path=MoveToNamespaceDialogTitle}"
HasHelpButton="True"
FocusManager.FocusedElement="{Binding ElementName=interfaceNameTextBox}"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
HasDialogFrame="True"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<Thickness x:Key="labelPadding">0, 5, 0, 2</Thickness>
<Thickness x:Key="textboxPadding">2</Thickness>
</Window.Resources>
<Grid Margin="11,6,11,11">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Label x:Uid="NamespaceLabel"
x:Name="NamespaceLabel"
Content="{Binding ElementName=dialog, Path=NamespaceLabelText}"
Padding="{StaticResource ResourceKey=labelPadding}"
Target="{Binding ElementName=NamespaceTextBox}" />
<TextBox x:Uid="NamespaceTextBox"
Name="NamespaceTextBox"
AutomationProperties.LabeledBy="{Binding ElementName=NamespaceLabel}"
Text="{Binding NamespaceName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Padding="{StaticResource ResourceKey=textboxPadding}"
GotFocus="SelectAllInTextBox" />
</StackPanel>
<StackPanel Grid.Row="1"
HorizontalAlignment="Right"
Margin="0, 11, 0, 0"
Orientation="Horizontal">
<Button x:Uid="OkButton"
Content="{Binding ElementName=dialog, Path=OK}"
Margin="0, 0, 0, 0"
Padding="9,2,9,2"
Click="OK_Click"
IsDefault="True"
MinWidth="73"
MinHeight="21"/>
<Button x:Uid="CancelButton"
Content="{Binding ElementName=dialog, Path=Cancel}"
Margin="7, 0, 0, 0"
Padding="9,2,9,2"
Click="Cancel_Click"
IsCancel="True"
MinWidth="73"
MinHeight="21"/>
</StackPanel>
</Grid>
</vs:DialogWindow>
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.VisualStudio.PlatformUI;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace
{
/// <summary>
/// Interaction logic for MoveToNamespaceDialog.xaml
/// </summary>
internal partial class MoveToNamespaceDialog : DialogWindow
{
private readonly MoveToNamespaceDialogViewModel _viewModel;
public string MoveToNamespaceDialogTitle => ServicesVSResources.Move_to_namespace;
public string NamespaceLabelText => ServicesVSResources.Namespace_colon;
public string OK => ServicesVSResources.OK;
public string Cancel => ServicesVSResources.Cancel;
internal MoveToNamespaceDialog(MoveToNamespaceDialogViewModel viewModel)
: base(helpTopic: "vs.csharp.refactoring.movetonamespace")
{
_viewModel = viewModel;
InitializeComponent();
DataContext = viewModel;
}
private void SelectAllInTextBox(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is TextBox textbox && Mouse.LeftButton == MouseButtonState.Released)
{
textbox.SelectAll();
}
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
private void OK_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
}
}
// 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 Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace
{
class MoveToNamespaceDialogViewModel : AbstractNotifyPropertyChanged
{
public MoveToNamespaceDialogViewModel(
IGlyphService glyphService,
string defaultNamespace)
{
NamespaceName = defaultNamespace;
}
private string _namespaceName;
public string NamespaceName
{
get => _namespaceName;
set => SetProperty(ref _namespaceName, value);
}
}
}
// 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.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.VisualStudio.Language.Intellisense;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace
{
[Export(typeof(IMoveToNamespaceOptionsService)), Shared]
internal class VisualStudioMoveToNamespaceOptionsService : IMoveToNamespaceOptionsService
{
private readonly IGlyphService _glyphService;
private readonly IThreadingContext _threadingContext;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public VisualStudioMoveToNamespaceOptionsService(IGlyphService glyphService, IThreadingContext threadingContext)
{
_glyphService = glyphService;
_threadingContext = threadingContext;
}
public async Task<MoveToNamespaceOptionsResult> GetChangeNamespaceOptionsAsync(
ISyntaxFactsService syntaxFactsService,
INotificationService notificationService,
string defaultNamespace,
CancellationToken cancellationToken)
{
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
var viewModel = new MoveToNamespaceDialogViewModel(
_glyphService,
defaultNamespace);
var dialog = new MoveToNamespaceDialog(viewModel);
var result = dialog.ShowModal();
if (result == true)
{
return new MoveToNamespaceOptionsResult(viewModel.NamespaceName);
}
else
{
return MoveToNamespaceOptionsResult.Cancelled;
}
}
}
}
......@@ -50,6 +50,10 @@
<Link>InternalUtilities\ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\ExpressionEvaluator\Core\Source\ExpressionCompiler\DkmExceptionUtilities.cs" Link="Implementation\EditAndContinue\Interop\DkmExceptionUtilities.cs" />
<Compile Update="Implementation\MoveToNamespace\MoveToNamespaceDialog.xaml.cs">
<DependentUpon>MoveToNamespaceDialog.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Implementation\PickMembers\PickMembersDialog.xaml.cs">
<DependentUpon>PickMembersDialog.xaml</DependentUpon>
</Compile>
......@@ -218,6 +222,9 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Implementation\MoveToNamespace\MoveToNamespaceDialog.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Implementation\PickMembers\PickMembersDialog.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
......
......@@ -1604,6 +1604,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Move To Namespace.
/// </summary>
internal static string Move_to_namespace {
get {
return ResourceManager.GetString("Move_to_namespace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Move up.
/// </summary>
......@@ -1631,6 +1640,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Namespace:.
/// </summary>
internal static string Namespace_colon {
get {
return ResourceManager.GetString("Namespace:", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Namespace: &apos;{0}&apos;.
/// </summary>
......
......@@ -1201,4 +1201,10 @@ I agree to all of the foregoing:</value>
<data name="Use_enhanced_colors_for_C_and_Basic" xml:space="preserve">
<value>Use enhanced colors for C# and Basic</value>
</data>
<data name="Move_to_namespace" xml:space="preserve">
<value>Move To Namespace</value>
</data>
<data name="Namespace" xml:space="preserve">
<value>Namespace</value>
</data>
</root>
\ No newline at end of file
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Obor názvů: {0}</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Namespace: {0}</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Espacio de nombres: "{0}"</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Espace de noms : '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Spazio dei nomi: '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">名前空間: '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">네임스페이스: '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Przestrzeń nazw: „{0}”</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Namespace: '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Пространство имен: "{0}"</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">Ad alanı: '{0}'</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">命名空间:“{0}”</target>
......
......@@ -127,6 +127,16 @@
<target state="new">Modifier preferences:</target>
<note />
</trans-unit>
<trans-unit id="Move_to_namespace">
<source>Move To Namespace</source>
<target state="new">Move To Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace">
<source>Namespace</source>
<target state="new">Namespace</target>
<note />
</trans-unit>
<trans-unit id="Namespace_0">
<source>Namespace: '{0}'</source>
<target state="translated">命名空間: '{0}'</target>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册