提交 69073f2f 编写于 作者: B Balaji Krishnan

Cut MoveType Dialog feature

Cut the following features:
1. Move type dialog
2. Make type partial.

Trimming the feature set being offered, targeting core scenarios and
dropping fringe features.
上级 2a9cf6dd
......@@ -59,8 +59,12 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa
else
{
var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey: null);
var renameFileAction = actions.Any(action => action.Title.StartsWith(RenameTypeCodeActionTitle));
Assert.False(renameFileAction, "Rename Type to match file name code action was not expected, but shows up.");
if (actions != null)
{
var renameFileAction = actions.Any(action => action.Title.StartsWith(RenameTypeCodeActionTitle));
Assert.False(renameFileAction, "Rename Type to match file name code action was not expected, but shows up.");
}
}
}
}
......@@ -91,8 +95,12 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa
else
{
var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey: null);
var renameFileAction = actions.Any(action => action.Title.StartsWith(RenameFileCodeActionTitle));
Assert.False(renameFileAction, "Rename File to match type code action was not expected, but shows up.");
if (actions != null)
{
var renameFileAction = actions.Any(action => action.Title.StartsWith(RenameFileCodeActionTitle));
Assert.False(renameFileAction, "Rename File to match type code action was not expected, but shows up.");
}
}
}
}
......
......@@ -21,13 +21,9 @@ internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarati
private class Editor
{
private readonly CancellationToken _cancellationToken;
private readonly MoveTypeOptionsResult _moveTypeOptions;
private readonly State _state;
private readonly TService _service;
private readonly bool _fromDialog;
private readonly bool _makeOuterTypesPartial;
private readonly bool _makeTypePartial;
private readonly bool _renameFile;
private readonly bool _renameType;
......@@ -36,20 +32,12 @@ private class Editor
State state,
bool renameFile,
bool renameType,
bool makeTypePartial,
bool makeOuterTypePartial,
MoveTypeOptionsResult moveTypeOptions,
bool fromDialog,
CancellationToken cancellationToken)
{
_renameFile = renameFile;
_makeTypePartial = makeTypePartial;
_makeOuterTypesPartial = makeOuterTypePartial || makeTypePartial;
_renameType = renameType;
_state = state;
_service = service;
this._moveTypeOptions = moveTypeOptions;
this._fromDialog = fromDialog;
this._cancellationToken = cancellationToken;
}
......@@ -68,11 +56,7 @@ internal async Task<IEnumerable<CodeActionOperation>> GetOperationsAsync()
return await RenameTypeToMatchFileAsync(solution).ConfigureAwait(false);
}
var documentName = _fromDialog
? _moveTypeOptions.NewFileName
: _state.TargetFileNameCandidate + _state.TargetFileExtension;
return await MoveTypeToNewFileAsync(documentName).ConfigureAwait(false);
return await MoveTypeToNewFileAsync(_state.TargetFileNameCandidate).ConfigureAwait(false);
}
private async Task<IEnumerable<CodeActionOperation>> MoveTypeToNewFileAsync(string documentName)
......@@ -131,18 +115,12 @@ private IEnumerable<CodeActionOperation> RenameFileToMatchTypeName(Solution solu
AddPartialModifiersToTypeChain(documentEditor, typeNode);
var membersToRemove = GetMembersToRemove(root, typeNode, removeDescendentsOfSelf: _makeTypePartial);
var membersToRemove = GetMembersToRemove(root, typeNode);
foreach (var member in membersToRemove)
{
documentEditor.RemoveNode(member, SyntaxRemoveOptions.KeepNoTrivia);
}
var memberToAdd = GetMemberToAdd(documentEditor.Generator, newDocumentName);
if (memberToAdd != null)
{
documentEditor.AddMember(typeNode, memberToAdd);
}
var modifiedRoot = documentEditor.GetChangedRoot();
// add an empty document to solution, so that we'll have options from the right context.
......@@ -162,40 +140,15 @@ private IEnumerable<CodeActionOperation> RenameFileToMatchTypeName(Solution solu
var documentEditor = await DocumentEditor.CreateAsync(sourceDocument, cancellationToken).ConfigureAwait(false);
AddPartialModifiersToTypeChain(documentEditor, typeNode);
if (!_makeTypePartial)
{
documentEditor.RemoveNode(typeNode, SyntaxRemoveOptions.KeepNoTrivia);
}
documentEditor.RemoveNode(typeNode, SyntaxRemoveOptions.KeepNoTrivia);
var updatedDocument = documentEditor.GetChangedDocument();
// TODO: make this optional -- shouldn't touch other parts of source document unless asked to.
return await CleanUpDocumentAsync(updatedDocument, cancellationToken).ConfigureAwait(false);
}
private SyntaxNode GetMemberToAdd(SyntaxGenerator generator, string newDocumentName)
{
if (!_makeOuterTypesPartial)
{
return null;
}
// we recognize filenames of that follow the pattern "OuterClass.InnerClass.cs"
// and generate code for this file, which will look like so:
// a partial definition of OuterClass and a nested private InnerClass.
var nameParts = Path.GetFileNameWithoutExtension(newDocumentName).Split(new char[] { '.' });
if (nameParts == null || nameParts.Count() != 2)
{
return null;
}
var innerTypeName = nameParts[1];
return generator.ClassDeclaration(innerTypeName, accessibility: Accessibility.Private);
}
// TODO: look to optimize the number of Ancestors and Descendants calls here.
// TODO: document this better and simplify code.
private static IEnumerable<SyntaxNode> GetMembersToRemove(
SyntaxNode root, TTypeDeclarationSyntax typeNode, bool removeDescendentsOfSelf)
SyntaxNode root, TTypeDeclarationSyntax typeNode)
{
var ancestorsAndSelfToKeep = typeNode
.AncestorsAndSelf()
......@@ -214,18 +167,7 @@ private SyntaxNode GetMemberToAdd(SyntaxGenerator generator, string newDocumentN
var membersOfAncestorsKept = ancestorsKept
.SelectMany(a => a.DescendantNodes().OfType<TMemberDeclarationSyntax>().Where(t => !t.Equals(typeNode) && t.Parent.Equals(a)));
var membersToRemove = topLevelMembersToRemove.Concat(membersOfAncestorsKept);
if (removeDescendentsOfSelf)
{
var descendentsOfSelf = typeNode
.DescendantNodes(descendIntoChildren: _ => true, descendIntoTrivia: false)
.OfType<TMemberDeclarationSyntax>();
membersToRemove = membersToRemove.Concat(descendentsOfSelf);
}
return membersToRemove;
return topLevelMembersToRemove.Concat(membersOfAncestorsKept);
}
private static bool IsTopLevelNamespaceOrTypeNode(SyntaxNode node)
......@@ -239,15 +181,12 @@ private void AddPartialModifiersToTypeChain(DocumentEditor documentEditor, TType
{
var semanticFacts = _state.SemanticDocument.Document.GetLanguageService<ISemanticFactsService>();
if (_makeOuterTypesPartial)
// If this is a nested type and if we're moving its definition to a new file
// we need to make the parent types partial in the origination file.
if (typeNode.Parent is TTypeDeclarationSyntax)
{
var typeChain = typeNode.Ancestors().OfType<TTypeDeclarationSyntax>();
if (_makeTypePartial)
{
typeChain = typeChain.Concat(typeNode);
}
foreach (var node in typeChain)
{
var symbol = (ITypeSymbol)_state.SemanticDocument.SemanticModel.GetDeclaredSymbol(node, _cancellationToken);
......
......@@ -15,8 +15,6 @@ private class MoveTypeCodeAction : CodeAction
private readonly TService _service;
private readonly bool _renameFile;
private readonly bool _makeTypePartial;
private readonly bool _makeOuterTypePartial;
private readonly string _title;
private readonly bool _renameType;
......@@ -24,14 +22,10 @@ private class MoveTypeCodeAction : CodeAction
TService service,
State state,
bool renameFile,
bool renameType,
bool makeTypePartial,
bool makeOuterTypePartial)
bool renameType)
{
_renameFile = renameFile;
_renameType = renameType;
_makeTypePartial = makeTypePartial;
_makeOuterTypePartial = makeOuterTypePartial;
_state = state;
_service = service;
_title = CreateDisplayText();
......@@ -43,29 +37,24 @@ private string CreateDisplayText()
{
return string.Format(
FeaturesResources.RenameFileToMatchTypeName,
_state.TargetFileNameCandidate + _state.TargetFileExtension);
_state.TargetFileNameCandidate);
}
else if (_renameType)
{
return string.Format(
FeaturesResources.RenameTypeToMatchFileName, _state.DocumentName);
}
else if (_makeTypePartial)
{
return string.Format(
FeaturesResources.MakePartialDefinitionForType, _state.TypeName);
}
return string.Format(
FeaturesResources.MoveTypeToFileName,
_state.TargetFileNameCandidate + _state.TargetFileExtension);
_state.TargetFileNameCandidate);
}
public override string Title => _title;
protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
{
var editor = new Editor(_service, _state, _renameFile, _renameType, _makeTypePartial, _makeOuterTypePartial, moveTypeOptions: null, fromDialog: false, cancellationToken: cancellationToken);
var editor = new Editor(_service, _state, _renameFile, _renameType, cancellationToken: cancellationToken);
return await editor.GetOperationsAsync().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.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.ProjectManagement;
namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarationSyntax, TNamespaceDeclarationSyntax, TMemberDeclarationSyntax, TCompilationUnitSyntax>
{
private class MoveTypeCodeActionWithOption : CodeActionWithOptions
{
private readonly State _state;
private readonly TService _service;
private readonly bool _makeTypePartial;
private readonly bool _makeOuterTypePartial;
private readonly string _title;
public MoveTypeCodeActionWithOption(
TService service,
State state,
bool makeTypePartial,
bool makeOuterTypePartial)
{
_service = service;
_state = state;
_makeTypePartial = makeTypePartial;
_makeOuterTypePartial = makeOuterTypePartial;
_title = CreateDisplayText();
}
private string CreateDisplayText()
{
if (_makeTypePartial)
{
return string.Format(
FeaturesResources.MakePartialDefinitionForTypeInNewFile, _state.TypeName);
}
return string.Format(FeaturesResources.MoveTypeToNewFile, _state.TypeName);
}
public override string Title => _title;
public Project Project => _state.SemanticDocument.Project;
public Document SyntacticDocument => _state.SemanticDocument.Document;
public override object GetOptions(CancellationToken cancellationToken)
{
var suggestedFileName = _state.TargetFileNameCandidate + _state.TargetFileExtension;
var workspaceServices = _state.SemanticDocument.Project.Solution.Workspace.Services;
var moveTypeOptionsService = workspaceServices.GetService<IMoveTypeOptionsService>();
var notificationService = workspaceServices.GetService<INotificationService>();
var projectManagementService = workspaceServices.GetService<IProjectManagementService>();
var syntaxFactsService = Project.LanguageServices.GetService<ISyntaxFactsService>();
return moveTypeOptionsService.GetMoveTypeOptions(suggestedFileName, SyntacticDocument, notificationService, projectManagementService, syntaxFactsService);
}
protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(object options, CancellationToken cancellationToken)
{
IEnumerable<CodeActionOperation> operations = null;
var moveTypeOptions = options as MoveTypeOptionsResult;
if (moveTypeOptions != null && !moveTypeOptions.IsCancelled)
{
// Move Type dialog is for moving types to new files.
// It cannot perform rename file or rename type operations.
var editor = new Editor(
_service,
state: _state,
renameFile: false,
renameType: false,
makeTypePartial: _makeTypePartial,
makeOuterTypePartial: _makeOuterTypePartial,
moveTypeOptions: moveTypeOptions,
fromDialog: true,
cancellationToken: cancellationToken);
operations = await editor.GetOperationsAsync().ConfigureAwait(false);
}
return operations;
}
}
}
}
......@@ -20,7 +20,6 @@ protected class State
public string TypeName { get; set; }
public string DocumentName { get; set; }
public string TargetFileNameCandidate { get; set; }
public string TargetFileExtension { get; set; }
private State(TService service,SemanticDocument document)
{
......@@ -72,8 +71,15 @@ internal static State Generate(TService service, SemanticDocument document, Text
TypeNode = typeDeclaration;
TypeName = typeSymbol.Name;
DocumentName = Path.GetFileNameWithoutExtension(this.SemanticDocument.Document.Name);
TargetFileNameCandidate = typeSymbol.Name;
TargetFileExtension = this.SemanticDocument.Document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb";
if (string.Equals(DocumentName, TypeName, StringComparison.CurrentCultureIgnoreCase))
{
// if type name matches document name, we have nothing more to do.
return false;
}
TargetFileNameCandidate =
typeSymbol.Name + (SemanticDocument.Document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb");
return true;
}
......
......@@ -62,78 +62,35 @@ public async Task<CodeRefactoring> GetRefactoringAsync(Document document, TextSp
private List<CodeAction> CreateActions(State state, CancellationToken cancellationToken)
{
var actions = new List<CodeAction>();
var targetFileName = state.TargetFileNameCandidate + state.TargetFileExtension;
var uiRequired = ProjectContainsTargetFile(state.SemanticDocument.Project, targetFileName, state.DocumentName, state.TypeName);
var isNestedType = IsNestedType(state.TypeNode);
var singleType = IsSingleTypeDeclarationInSourceDocument(state.SemanticDocument.Root);
var typeSymbol = (ITypeSymbol)state.SemanticDocument.SemanticModel.GetDeclaredSymbol(state.TypeNode, cancellationToken);
var semanticFacts = state.SemanticDocument.Document.GetLanguageService<ISemanticFactsService>();
var isPartial = semanticFacts.IsPartial(typeSymbol);
if (singleType)
{
// one type declaration in current document. No moving around required, just sync
// document name and type name by offering rename in both directions between type and document.
AddSimpleCodeAction(actions, state, uiRequired, renameFile: true);
AddSimpleCodeAction(actions, state, uiRequired, renameType: true);
AddSimpleCodeAction(actions, state, renameFile: true);
AddSimpleCodeAction(actions, state, renameType: true);
}
else
{
// multiple type declarations in current document.
AddSimpleCodeAction(actions, state, uiRequired, newFile: true, makeOuterTypePartial: isNestedType);
// multiple type declarations in current document. so, move to new file.
AddSimpleCodeAction(actions, state);
}
// Add actions that bring up UI dialog.
AddCodeActionsWithUI(actions, state, makeTypePartial: !isPartial, makeOuterTypePartial: isNestedType);
return actions;
}
private void AddCodeActionsWithUI(
List<CodeAction> actions,
State state,
bool makeTypePartial,
bool makeOuterTypePartial)
{
// make this type declaration partial and add a new partial part in a new file.
if (makeTypePartial)
{
actions.Add(
GetCodeActionWithUI(state, makeTypePartial, makeOuterTypePartial));
}
// this gives an option for the user specify a custom file name for the normal move scenario.
actions.Add(
GetCodeActionWithUI(
state, makeTypePartial: false, makeOuterTypePartial: makeOuterTypePartial));
}
private MoveTypeCodeActionWithOption GetCodeActionWithUI(
State state, bool makeTypePartial, bool makeOuterTypePartial) =>
new MoveTypeCodeActionWithOption(
(TService)this,
state: state,
makeTypePartial: makeTypePartial,
makeOuterTypePartial: makeOuterTypePartial);
private void AddSimpleCodeAction(
List<CodeAction> actions,
State state,
bool uiRequired,
bool renameFile = false,
bool renameType = false,
bool newFile = false,
bool makeTypePartial = false,
bool makeOuterTypePartial = false)
bool renameType = false)
{
// to add the codeaction without UI dialog, ensure scenario does not require user interaction
// and atleast one valid case exists.
if ((renameFile || renameType || newFile || makeTypePartial || makeOuterTypePartial) && !uiRequired)
{
actions.Add(
new MoveTypeCodeAction(
(TService)this, state, renameFile, renameType, makeTypePartial, makeOuterTypePartial));
}
actions.Add(
new MoveTypeCodeAction(
(TService)this, state, renameFile, renameType));
}
}
}
// 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.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.ProjectManagement;
namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal interface IMoveTypeOptionsService : IWorkspaceService
{
MoveTypeOptionsResult GetMoveTypeOptions(
string suggestedFileName,
Document document,
INotificationService notificationService,
IProjectManagementService projectManagementService,
ISyntaxFactsService syntaxFactsService);
}
}
// 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;
namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal class MoveTypeOptionsResult
{
public static readonly MoveTypeOptionsResult Cancelled = new MoveTypeOptionsResult(isCancelled: true);
public bool IsCancelled { get; }
public string NewFileName { get; }
public MoveTypeOptionsResult(string newFileName, bool isCancelled = false)
{
this.NewFileName = newFileName;
this.IsCancelled = isCancelled;
}
private MoveTypeOptionsResult(bool isCancelled)
{
this.IsCancelled = isCancelled;
}
}
}
......@@ -158,12 +158,9 @@
<Compile Include="CodeRefactorings\MoveType\MoveTypeCodeRefactoringProvider.cs" />
<Compile Include="CodeRefactorings\MoveType\AbstractMoveTypeService.Editor.cs" />
<Compile Include="CodeRefactorings\MoveType\AbstractMoveTypeService.MoveTypeCodeAction.cs" />
<Compile Include="CodeRefactorings\MoveType\AbstractMoveTypeService.MoveTypeCodeActionWithOption.cs" />
<Compile Include="CodeRefactorings\MoveType\AbstractMoveTypeService.State.cs" />
<Compile Include="CodeRefactorings\MoveType\AbstractMoveTypeService.cs" />
<Compile Include="CodeRefactorings\MoveType\IMoveTypeOptionsService.cs" />
<Compile Include="CodeRefactorings\MoveType\IMoveTypeService.cs" />
<Compile Include="CodeRefactorings\MoveType\MoveTypeOptionsResult.cs" />
<Compile Include="CodeRefactorings\PredefinedCodeRefactoringProviderNames.cs" />
<Compile Include="CodeRefactorings\ServicesLayerCodeActionHelpersService.cs" />
<Compile Include="CodeRefactorings\WorkspaceServices\IAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs" />
......
<vs:DialogWindow
x:Uid="MoveTypeDialog"
x:Name="dialog"
x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.MoveType.MoveTypeDialog"
x:ClassModifier="internal"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
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.MoveType"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="{Binding ElementName=dialog, Path=MoveTypeDialogTitle}"
Height="125"
Width="431"
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterScreen"
SizeToContent="Width">
<Grid>
<Grid.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
Name="FolderLabel"
Content="{Binding ProjectName}"
HorizontalAlignment="Left"
Margin="5 0 0 0"
VerticalAlignment="Center"
Height="26"
FontWeight="Bold" />
<TextBox
x:Uid="FileNameTextBoxUid"
Grid.Row="0"
Grid.Column="1"
Name="FileNameTextBox"
Text="{Binding FileName, Mode=TwoWay}"
VerticalContentAlignment="Center"
Height="23"
TextWrapping="Wrap"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
MinWidth="210" />
<Button
Grid.Row="0"
Grid.Column="2"
Content="{Binding ElementName=dialog, Path=AddFile}"
HorizontalAlignment="Center"
Margin="10,0"
VerticalAlignment="Center"
Width="75"
Height="23"
IsDefault="True"
Name="AddFileButton"
Click="AddFileButton_Click" />
<CheckBox
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Name="RemoveUnusedUsingsCheckBox"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="5,0"
Height="26"
Content="{Binding ElementName=dialog, Path=RemoveUnusedUsings}"
IsChecked="{Binding RemoveUnusedUsings, Mode=TwoWay}"/>
</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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.VisualStudio.PlatformUI;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveType
{
/// <summary>
/// Interaction logic for MoveTypeDialog.xaml
/// </summary>
internal partial class MoveTypeDialog : DialogWindow
{
private readonly MoveTypeDialogViewModel _viewModel;
public string MoveTypeDialogTitle => ServicesVSResources.MoveTypeDialogTitle;
public string AddFile => ServicesVSResources.AddFile;
public string RemoveUnusedUsings => ServicesVSResources.RemoveUnusedUsings;
// TODO: NYI
public string Folder { get; }
public MoveTypeDialog(MoveTypeDialogViewModel viewModel)
{
_viewModel = viewModel;
InitializeComponent();
DataContext = viewModel;
this.PreviewKeyDown += new KeyEventHandler(CloseOnEscape);
}
private void CloseOnEscape(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Close();
}
}
private void AddFileButton_Click(object sender, RoutedEventArgs e)
{
if (_viewModel.TrySubmit())
{
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 System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.ProjectManagement;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveType
{
internal class MoveTypeDialogViewModel : AbstractNotifyPropertyChanged
{
private string _fileName;
public string FileName
{
get { return _fileName; }
set { SetProperty(ref _fileName, value); }
}
private string _projectName;
public string ProjectName
{
get { return _projectName; }
set { SetProperty(ref _projectName, value); }
}
private bool _removeUnusedUsings;
public bool RemoveUnusedUsings
{
get { return _removeUnusedUsings; }
set { SetProperty(ref _removeUnusedUsings, value); }
}
internal MoveTypeDialogViewModel(
string suggestedFileName,
Document document,
INotificationService notificationService,
IProjectManagementService projectManagementService,
ISyntaxFactsService syntaxFactsService)
{
ProjectName = document.Project.Name + " " + Path.DirectorySeparatorChar;
FileName = suggestedFileName;
}
internal bool TrySubmit()
{
// TODO: NYI. make file checks and raise appropriate failure messages.
return 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 System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeRefactorings.MoveType;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.ProjectManagement;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveType
{
[ExportWorkspaceServiceFactory(typeof(IMoveTypeOptionsService), ServiceLayer.Host), Shared]
internal class VisualStudioMoveTypeOptionsServiceFactory : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new VisualStudioMoveTypeOptionsService();
}
private class VisualStudioMoveTypeOptionsService : IMoveTypeOptionsService
{
public MoveTypeOptionsResult GetMoveTypeOptions(
string suggestedFileName,
Document document,
INotificationService notificationService,
IProjectManagementService projectManagementService,
ISyntaxFactsService syntaxFactsService)
{
var viewModel = new MoveTypeDialogViewModel(suggestedFileName, document, notificationService, projectManagementService, syntaxFactsService);
var dialog = new MoveTypeDialog(viewModel);
var result = dialog.ShowModal();
if (result.HasValue && result.Value)
{
var fileName = viewModel.FileName.Trim();
return new MoveTypeOptionsResult(fileName);
}
else
{
return MoveTypeOptionsResult.Cancelled;
}
}
}
}
}
......@@ -699,13 +699,4 @@ Additional information: {1}</value>
<data name="Prefer_predefined_type" xml:space="preserve">
<value>Prefer predefined type</value>
</data>
<data name="AddFile" xml:space="preserve">
<value>Add File</value>
</data>
<data name="MoveTypeDialogTitle" xml:space="preserve">
<value>Move Type To File...</value>
</data>
<data name="RemoveUnusedUsings" xml:space="preserve">
<value>Remove unused usings in source file</value>
</data>
</root>
\ No newline at end of file
......@@ -45,7 +45,7 @@
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\ConcurrentLruCache.cs">
<Link>Shared\ConcurrentLruCache.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\Interop\IVsSQM.cs" />
<Compile Include="..\..\..\Compilers\Core\Portable\Interop\IVsSQM.cs" />
<Compile Include="..\..\..\Compilers\Shared\ShadowCopyAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
......@@ -85,11 +85,6 @@
<Compile Include="Implementation\Library\VsNavInfo\NavInfoNode.cs" />
<Compile Include="Implementation\Log\VisualStudioErrorLogger.cs" />
<Compile Include="Implementation\AnalyzerDependency\MissingAnalyzerDependency.cs" />
<Compile Include="Implementation\MoveType\MoveTypeDialog.xaml.cs">
<DependentUpon>MoveTypeDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Implementation\MoveType\MoveTypeDialogViewModel.cs" />
<Compile Include="Implementation\MoveType\VisualStudioMoveTypeOptionsServiceFactory.cs" />
<Compile Include="Implementation\Preview\ReferenceChange.MetadataReferenceChange.cs" />
<Compile Include="Implementation\Preview\ReferenceChange.AnalyzerReferenceChange.cs" />
<Compile Include="Implementation\Preview\ReferenceChange.ProjectReferenceChange.cs" />
......@@ -700,10 +695,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Implementation\MoveType\MoveTypeDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Implementation\PreviewPane\PreviewPane.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册