9
9
using Microsoft . VisualStudio . Shell ;
10
10
using Microsoft . VisualStudio . Text ;
11
11
using Microsoft . VisualStudio . Threading ;
12
+ // Debug collides with Microsoft.VisualStudio.ProjectSystem.VS.Debug
13
+ using DiagDebug = System . Diagnostics . Debug ;
12
14
using Path = System . IO . Path ;
13
- using static System . Diagnostics . Debug ;
14
15
using static Microsoft . CodeAnalysis . Rename . Renamer ;
15
16
16
17
namespace Microsoft . VisualStudio . ProjectSystem . VS . Rename
@@ -31,7 +32,8 @@ internal class FileMoveNotificationListener : IFileMoveNotificationListener
31
32
private readonly IRoslynServices _roslynServices ;
32
33
private readonly IVsService < SVsSettingsPersistenceManager , ISettingsManager > _settingsManagerService ;
33
34
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 ( ) ;
35
37
private string ? _renameMessage ;
36
38
37
39
[ ImportingConstructor ]
@@ -58,16 +60,13 @@ public FileMoveNotificationListener(
58
60
59
61
public async Task OnBeforeFilesMovedAsync ( IReadOnlyCollection < IFileMoveItem > items )
60
62
{
61
- // Always start with an empty collection when activated.
62
- _renameActionSets . Clear ( ) ;
63
-
64
63
Project ? project = _workspace . CurrentSolution . Projects . FirstOrDefault ( p => StringComparers . Paths . Equals ( p . FilePath , _unconfiguredProject . FullPath ) ) ;
65
64
if ( project is null )
66
65
{
67
66
return ;
68
67
}
69
68
70
- foreach ( IFileMoveItem itemToMove in GetFilesToMoveRecursive ( items ) )
69
+ foreach ( IFileMoveItem itemToMove in GetFilesToMove ( items ) )
71
70
{
72
71
Document ? currentDocument = project . Documents . FirstOrDefault ( d => StringComparers . Paths . Equals ( d . FilePath , itemToMove . Source ) ) ;
73
72
if ( currentDocument is null )
@@ -93,15 +92,19 @@ public async Task OnBeforeFilesMovedAsync(IReadOnlyCollection<IFileMoveItem> ite
93
92
// The text in English is "Sync namespace to folder structure".
94
93
_renameMessage ??= renameActionSet . ApplicableActions . First ( ) . GetDescription ( ) ;
95
94
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 ) ;
97
97
}
98
98
99
99
return ;
100
100
101
- static IEnumerable < IFileMoveItem > GetFilesToMoveRecursive ( IEnumerable < IFileMoveItem > items )
101
+ static IEnumerable < IFileMoveItem > GetFilesToMove ( IEnumerable < IFileMoveItem > items )
102
102
{
103
- foreach ( IFileMoveItem item in items )
103
+ var itemQueue = new Queue < IFileMoveItem > ( items ) ;
104
+ while ( itemQueue . Count > 0 )
104
105
{
106
+ IFileMoveItem item = itemQueue . Dequeue ( ) ;
107
+
105
108
// Termination condition
106
109
if ( item is { WithinProject : true , IsFolder : false , IsLinked : false } &&
107
110
StringComparers . ItemTypes . Equals ( item . ItemType , Compile . SchemaName ) )
@@ -110,13 +113,13 @@ static IEnumerable<IFileMoveItem> GetFilesToMoveRecursive(IEnumerable<IFileMoveI
110
113
continue ;
111
114
}
112
115
113
- // Recursive folder navigation
116
+ // Folder navigation
114
117
if ( item is { IsFolder : true } and ICopyPasteItem copyPasteItem )
115
118
{
116
119
IEnumerable < IFileMoveItem > children = copyPasteItem . Children . Select ( c => c as IFileMoveItem ) . WhereNotNull ( ) ;
117
- foreach ( IFileMoveItem child in GetFilesToMoveRecursive ( children ) )
120
+ foreach ( IFileMoveItem child in children )
118
121
{
119
- yield return child ;
122
+ itemQueue . Enqueue ( child ) ;
120
123
}
121
124
}
122
125
}
@@ -125,8 +128,10 @@ static IEnumerable<IFileMoveItem> GetFilesToMoveRecursive(IEnumerable<IFileMoveI
125
128
126
129
public async Task OnAfterFileMoveAsync ( )
127
130
{
128
- if ( ! _renameActionSets . Any ( ) || ! await IsEnabledOrConfirmedAsync ( ) )
131
+ if ( ! _renameActionSetByFilePath . Any ( ) || ! await IsEnabledOrConfirmedAsync ( ) )
129
132
{
133
+ // Clear the collection since the user declined (or has disabled) the rename namespace option.
134
+ _renameActionSetByFilePath . Clear ( ) ;
130
135
return ;
131
136
}
132
137
@@ -140,7 +145,7 @@ public async Task OnAfterFileMoveAsync()
140
145
message : _renameMessage ! ,
141
146
allowCancel : true ,
142
147
asyncMethod : ApplyRenamesAsync ,
143
- totalSteps : _renameActionSets . Count ) ;
148
+ totalSteps : _renameActionSetByFilePath . Count ) ;
144
149
} ) ;
145
150
146
151
return ;
@@ -157,17 +162,19 @@ async Task ApplyRenamesAsync(IWaitContext context)
157
162
Solution solution = _workspace . CurrentSolution ;
158
163
159
164
int currentStep = 1 ;
160
- foreach ( KeyValuePair < string , RenameDocumentActionSet > renameActionSet in _renameActionSets )
165
+ foreach ( ( string filePath , RenameDocumentActionSet renameActionSet ) in _renameActionSetByFilePath )
161
166
{
162
167
// 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 ) ) ;
164
169
165
- solution = await renameActionSet . Value . UpdateSolutionAsync ( solution , token ) ;
170
+ solution = await renameActionSet . UpdateSolutionAsync ( solution , token ) ;
166
171
}
167
172
168
173
await _threadingService . SwitchToUIThread ( token ) ;
169
174
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 ( ) ;
171
178
}
172
179
173
180
async Task < bool > IsEnabledOrConfirmedAsync ( )
0 commit comments