Skip to content

Commit db5b56d

Browse files
committed
Address PR comments.
1 parent 61f85d4 commit db5b56d

File tree

1 file changed

+25
-18
lines changed

1 file changed

+25
-18
lines changed

src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Rename/FileMoveNotificationListener.cs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
using Microsoft.VisualStudio.Shell;
1010
using Microsoft.VisualStudio.Text;
1111
using Microsoft.VisualStudio.Threading;
12+
// Debug collides with Microsoft.VisualStudio.ProjectSystem.VS.Debug
13+
using DiagDebug = System.Diagnostics.Debug;
1214
using Path = System.IO.Path;
13-
using static System.Diagnostics.Debug;
1415
using static Microsoft.CodeAnalysis.Rename.Renamer;
1516

1617
namespace Microsoft.VisualStudio.ProjectSystem.VS.Rename
@@ -31,7 +32,8 @@ internal class FileMoveNotificationListener : IFileMoveNotificationListener
3132
private readonly IRoslynServices _roslynServices;
3233
private readonly IVsService<SVsSettingsPersistenceManager, ISettingsManager> _settingsManagerService;
3334

34-
private readonly Dictionary<string, RenameDocumentActionSet> _renameActionSets = new();
35+
// The file-paths are the full disk path of the source file (path prior to moving the item).
36+
private readonly Dictionary<string, RenameDocumentActionSet> _renameActionSetByFilePath = new();
3537
private string? _renameMessage;
3638

3739
[ImportingConstructor]
@@ -58,16 +60,13 @@ public FileMoveNotificationListener(
5860

5961
public async Task OnBeforeFilesMovedAsync(IReadOnlyCollection<IFileMoveItem> items)
6062
{
61-
// Always start with an empty collection when activated.
62-
_renameActionSets.Clear();
63-
6463
Project? project = _workspace.CurrentSolution.Projects.FirstOrDefault(p => StringComparers.Paths.Equals(p.FilePath, _unconfiguredProject.FullPath));
6564
if (project is null)
6665
{
6766
return;
6867
}
6968

70-
foreach (IFileMoveItem itemToMove in GetFilesToMoveRecursive(items))
69+
foreach (IFileMoveItem itemToMove in GetFilesToMove(items))
7170
{
7271
Document? currentDocument = project.Documents.FirstOrDefault(d => StringComparers.Paths.Equals(d.FilePath, itemToMove.Source));
7372
if (currentDocument is null)
@@ -93,15 +92,19 @@ public async Task OnBeforeFilesMovedAsync(IReadOnlyCollection<IFileMoveItem> ite
9392
// The text in English is "Sync namespace to folder structure".
9493
_renameMessage ??= renameActionSet.ApplicableActions.First().GetDescription();
9594

96-
_renameActionSets.Add(itemToMove.Source, renameActionSet);
95+
// Add the full source file-path of the item as the key for the rename action set.
96+
_renameActionSetByFilePath.Add(itemToMove.Source, renameActionSet);
9797
}
9898

9999
return;
100100

101-
static IEnumerable<IFileMoveItem> GetFilesToMoveRecursive(IEnumerable<IFileMoveItem> items)
101+
static IEnumerable<IFileMoveItem> GetFilesToMove(IEnumerable<IFileMoveItem> items)
102102
{
103-
foreach (IFileMoveItem item in items)
103+
var itemQueue = new Queue<IFileMoveItem>(items);
104+
while(itemQueue.Count > 0)
104105
{
106+
IFileMoveItem item = itemQueue.Dequeue();
107+
105108
// Termination condition
106109
if (item is { WithinProject: true, IsFolder: false, IsLinked: false } &&
107110
StringComparers.ItemTypes.Equals(item.ItemType, Compile.SchemaName))
@@ -110,13 +113,13 @@ static IEnumerable<IFileMoveItem> GetFilesToMoveRecursive(IEnumerable<IFileMoveI
110113
continue;
111114
}
112115

113-
// Recursive folder navigation
116+
// Folder navigation
114117
if (item is { IsFolder: true } and ICopyPasteItem copyPasteItem)
115118
{
116119
IEnumerable<IFileMoveItem> children = copyPasteItem.Children.Select(c => c as IFileMoveItem).WhereNotNull();
117-
foreach (IFileMoveItem child in GetFilesToMoveRecursive(children))
120+
foreach (IFileMoveItem child in children)
118121
{
119-
yield return child;
122+
itemQueue.Enqueue(child);
120123
}
121124
}
122125
}
@@ -125,8 +128,10 @@ static IEnumerable<IFileMoveItem> GetFilesToMoveRecursive(IEnumerable<IFileMoveI
125128

126129
public async Task OnAfterFileMoveAsync()
127130
{
128-
if (!_renameActionSets.Any() || !await IsEnabledOrConfirmedAsync())
131+
if (!_renameActionSetByFilePath.Any() || !await IsEnabledOrConfirmedAsync())
129132
{
133+
// Clear the collection since the user declined (or has disabled) the rename namespace option.
134+
_renameActionSetByFilePath.Clear();
130135
return;
131136
}
132137

@@ -140,7 +145,7 @@ public async Task OnAfterFileMoveAsync()
140145
message: _renameMessage!,
141146
allowCancel: true,
142147
asyncMethod: ApplyRenamesAsync,
143-
totalSteps: _renameActionSets.Count);
148+
totalSteps: _renameActionSetByFilePath.Count);
144149
});
145150

146151
return;
@@ -157,17 +162,19 @@ async Task ApplyRenamesAsync(IWaitContext context)
157162
Solution solution = _workspace.CurrentSolution;
158163

159164
int currentStep = 1;
160-
foreach (KeyValuePair<string, RenameDocumentActionSet> renameActionSet in _renameActionSets)
165+
foreach ((string filePath, RenameDocumentActionSet renameActionSet) in _renameActionSetByFilePath)
161166
{
162167
// Display the filename being updated to the user in the progress dialog.
163-
context.Update(currentStep: currentStep++, progressText: Path.GetFileName(renameActionSet.Key));
168+
context.Update(currentStep: currentStep++, progressText: Path.GetFileName(filePath));
164169

165-
solution = await renameActionSet.Value.UpdateSolutionAsync(solution, token);
170+
solution = await renameActionSet.UpdateSolutionAsync(solution, token);
166171
}
167172

168173
await _threadingService.SwitchToUIThread(token);
169174
bool areChangesApplied = _roslynServices.ApplyChangesToSolution(_workspace, solution);
170-
Assert(areChangesApplied, "ApplyChangesToSolution returned false");
175+
DiagDebug.Assert(areChangesApplied, "ApplyChangesToSolution returned false");
176+
// Clear the collection after it has been processed.
177+
_renameActionSetByFilePath.Clear();
171178
}
172179

173180
async Task<bool> IsEnabledOrConfirmedAsync()

0 commit comments

Comments
 (0)