Skip to content

Commit afbdee1

Browse files
committed
Only save and recover selections for open code panes
Accessing a code pane has the side effect of opening it if it is not open already. To avoid opening windows because of selection recovery, the recovery has to be restricted to modules already open.
1 parent 39bd248 commit afbdee1

File tree

5 files changed

+128
-43
lines changed

5 files changed

+128
-43
lines changed

Rubberduck.Parsing/Rewriter/AttributesRewriteSession.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ protected override bool TryRewriteInternal()
2828
//The suspension ensures that only one parse gets executed instead of two for each rewritten module.
2929
GuaranteeReparseAfterRewrite();
3030
PrimeActiveCodePaneRecovery();
31+
//Attribute rewrites close the affected code panes, so we have to recover the open state.
32+
PrimeOpenStateRecovery();
3133

3234
var result = _parseManager.OnSuspendParser(this, new[] {ParserState.Ready, ParserState.ResolvedDeclarations}, ExecuteAllRewriters);
3335
if(result != SuspensionResult.Completed)
@@ -61,17 +63,20 @@ private void PrimeActiveCodePaneRecovery()
6163
SelectionRecoverer.RecoverActiveCodePaneOnNextParse();
6264
}
6365

66+
private void PrimeOpenStateRecovery()
67+
{
68+
SelectionRecoverer.SaveOpenState(CheckedOutModules);
69+
SelectionRecoverer.RecoverOpenStateOnNextParse();
70+
}
71+
6472
private void ExecuteAllRewriters()
6573
{
66-
//Attribute rewrites close the affected code panes, so we have to recover the open state.
67-
SelectionRecoverer.SaveOpenState(CheckedOutModuleRewriters.Keys);
6874
foreach (var module in CheckedOutModuleRewriters.Keys)
6975
{
7076
//We have to mark the modules explicitly as modified because attributes only changes do not alter the code pane code.
7177
_parseManager.MarkAsModified(module);
7278
CheckedOutModuleRewriters[module].Rewrite();
7379
}
74-
SelectionRecoverer.RecoverOpenState();
7580
}
7681
}
7782
}

Rubberduck.Parsing/Rewriter/RewriteSessionBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public bool TryRewrite()
103103

104104
private void PrimeSelectionRecovery()
105105
{
106-
SelectionRecoverer.SaveSelections(CheckedOutModuleRewriters.Keys);
106+
SelectionRecoverer.SaveSelections(CheckedOutModules);
107107

108108
foreach (var (module, rewriter) in CheckedOutModuleRewriters)
109109
{

Rubberduck.Parsing/Rewriter/SelectionRecoverer.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public SelectionRecoverer(ISelectionService selectionService, IParseManager pars
2828
public void SaveSelections(IEnumerable<QualifiedModuleName> modules)
2929
{
3030
_savedSelections.Clear();
31-
foreach (var module in modules.Distinct())
31+
var openModules = _selectionService.OpenModules();
32+
33+
foreach (var module in modules.Where(module => openModules.Contains(module)).Distinct())
3234
{
3335
var selection = _selectionService.Selection(module);
3436
if (selection.HasValue)
@@ -48,7 +50,10 @@ public void AdjustSavedSelection(QualifiedModuleName module, Selection selection
4850

4951
public void ReplaceSavedSelection(QualifiedModuleName module, Selection replacementSelection)
5052
{
51-
_savedSelections[module] = replacementSelection;
53+
if (_savedSelections.ContainsKey(module) || _selectionService.OpenModules().Contains(module))
54+
{
55+
_savedSelections[module] = replacementSelection;
56+
}
5257
}
5358

5459
public void RecoverSavedSelections()

RubberduckTests/Rewriter/AttributesRewriteSessionTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,18 @@ public void TargetsAttributesCode()
9191

9292
[Test]
9393
[Category("Rewriter")]
94-
public void CallsRecoverOpenStateOnRewrite()
94+
public void CallsRecoverOpenStateOnNextParseOnRewrite()
9595
{
9696
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
97-
selectionRecovererMock.Setup(m => m.RecoverOpenState());
97+
selectionRecovererMock.Setup(m => m.RecoverOpenStateOnNextParse());
9898

9999
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
100100
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
101101

102102
rewriteSession.CheckOutModuleRewriter(module);
103103
rewriteSession.TryRewrite();
104104

105-
selectionRecovererMock.Verify(m => m.RecoverOpenState(), Times.Once);
105+
selectionRecovererMock.Verify(m => m.RecoverOpenStateOnNextParse(), Times.Once);
106106
}
107107

108108
[Test]
@@ -125,20 +125,20 @@ public void SavesOpenStateForCheckedOutModulesOnRewrite()
125125

126126
[Test]
127127
[Category("Rewriter")]
128-
public void SavesOpenStateBeforeRestoringItOnRewrite()
128+
public void SavesOpenStateBeforeRecoverOpenStateOnNextParseOnRewrite()
129129
{
130130
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
131131
var lastOperation = string.Empty;
132132
selectionRecovererMock.Setup(m => m.SaveOpenState(It.IsAny<IEnumerable<QualifiedModuleName>>())).Callback(() => lastOperation = "SaveOpenState");
133-
selectionRecovererMock.Setup(m => m.RecoverOpenState()).Callback(() => lastOperation = "RecoverOpenState");
133+
selectionRecovererMock.Setup(m => m.RecoverOpenStateOnNextParse()).Callback(() => lastOperation = "RecoverOpenStateOnNextParse");
134134

135135
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
136136
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
137137

138138
rewriteSession.CheckOutModuleRewriter(module);
139139
rewriteSession.TryRewrite();
140140

141-
Assert.AreEqual("RecoverOpenState", lastOperation);
141+
Assert.AreEqual("RecoverOpenStateOnNextParse", lastOperation);
142142
}
143143

144144
[Test]

RubberduckTests/Rewriter/SelectionRecovererTests.cs

Lines changed: 106 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@ public void SetsExactlySavedSelectionsOnRecoverSelections()
3535
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
3636
}
3737

38+
[Test]
39+
[Category("Rewriting")]
40+
public void SavesSelectionsOnlyForOpenCodePanes()
41+
{
42+
var selectionServiceMock = TestSelectionServiceMock();
43+
var parseManager = new Mock<IParseManager>().Object;
44+
var selectionRecoverer = new SelectionRecoverer(selectionServiceMock.Object, parseManager);
45+
46+
selectionServiceMock.Setup(m => m.OpenModules())
47+
.Returns(() => _testModuleSelections.Skip(1).Select(qs => qs.QualifiedName).ToList());
48+
49+
selectionRecoverer.SaveSelections(_testModuleSelections.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
50+
51+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[0].QualifiedName), Times.Never);
52+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[1].QualifiedName), Times.Once);
53+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[2].QualifiedName), Times.Never);
54+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[3].QualifiedName), Times.Never);
55+
}
56+
3857
[Test]
3958
[Category("Rewriting")]
4059
public void SetsExactlyLastSavedSelectionsOnRecoverSelectionsAfterMultipleSaves()
@@ -97,41 +116,64 @@ public void SetsReplacementSelectionOnRecoverSelections_SelectionSavedPreviously
97116

98117
selectionRecoverer.SaveSelections(_testModuleSelections
99118
.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
100-
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[2].QualifiedName, selectionReplacement);
119+
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[0].QualifiedName, selectionReplacement);
101120
selectionRecoverer.RecoverSavedSelections();
102121

103-
foreach (var qualifiedSelection in _testModuleSelections.Take(2))
104-
{
105-
selectionServiceMock.Verify(
106-
m => m.TrySetSelection(qualifiedSelection.QualifiedName, qualifiedSelection.Selection), Times.Once);
107-
}
108-
109122
selectionServiceMock.Verify(
110-
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, selectionReplacement), Times.Once);
123+
m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, selectionReplacement), Times.Once);
124+
selectionServiceMock.Verify(
125+
m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection),
126+
Times.Once);
127+
selectionServiceMock.Verify(
128+
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
111129
}
112130

113131
[Test]
114132
[Category("Rewriting")]
115-
public void SetsReplacementSelectionOnRecoverSelections_SelectionNotSavedPreviously()
133+
public void SetReplacementSelectionOnRecoverSelections_SelectionNotSavedPreviously_ModuleOpen()
116134
{
117135
var selectionServiceMock = TestSelectionServiceMock();
118136
var parseManager = new Mock<IParseManager>().Object;
119137
var selectionRecoverer = new SelectionRecoverer(selectionServiceMock.Object, parseManager);
120138

121139
var selectionReplacement = new Selection(22, 2, 44, 5);
122140

123-
selectionRecoverer.SaveSelections(_testModuleSelections
124-
.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
125-
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[0].QualifiedName, selectionReplacement);
141+
selectionRecoverer.SaveSelections(_testModuleSelections.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
142+
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[2].QualifiedName, selectionReplacement);
126143
selectionRecoverer.RecoverSavedSelections();
127144

128-
selectionServiceMock.Verify(
129-
m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, selectionReplacement), Times.Once);
130-
selectionServiceMock.Verify(
131-
m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection),
132-
Times.Once);
133-
selectionServiceMock.Verify(
134-
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
145+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, _testModuleSelections[0].Selection), Times.Once);
146+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection), Times.Once);
147+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, selectionReplacement), Times.Once);
148+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[3].QualifiedName, It.IsAny<Selection>()), Times.Never);
149+
}
150+
151+
[Test]
152+
[Category("Rewriting")]
153+
public void DoesNotSaveOrSetReplacementSelectionOnRecoverSelections_SelectionNotSavedPreviously_ModuleNotOpen()
154+
{
155+
var selectionServiceMock = TestSelectionServiceMock();
156+
var parseManager = new Mock<IParseManager>().Object;
157+
var selectionRecoverer = new SelectionRecoverer(selectionServiceMock.Object, parseManager);
158+
159+
selectionServiceMock.Setup(m => m.OpenModules())
160+
.Returns(() => _testModuleSelections.Take(2).Select(qs => qs.QualifiedName).ToList());
161+
162+
var selectionReplacement = new Selection(22, 2, 44, 5);
163+
164+
selectionRecoverer.SaveSelections(_testModuleSelections.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
165+
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[2].QualifiedName, selectionReplacement);
166+
selectionRecoverer.RecoverSavedSelections();
167+
168+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[0].QualifiedName), Times.Once);
169+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[1].QualifiedName), Times.Once);
170+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[2].QualifiedName), Times.Never);
171+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[3].QualifiedName), Times.Never);
172+
173+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, _testModuleSelections[0].Selection), Times.Once);
174+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection), Times.Once);
175+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
176+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[3].QualifiedName, It.IsAny<Selection>()), Times.Never);
135177
}
136178

137179
[Test]
@@ -288,34 +330,67 @@ public void SetsModifiedSelectionAfterOffsetIsAppliedOnParseAfterRecoverSelectio
288330
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
289331
}
290332

333+
334+
291335
[Test]
292336
[Category("Rewriting")]
293-
public void SetsReplacementSelectionOnParseAfterRecoverSelectionsOnNextParse_SelectionSavedPreviously()
337+
public void SetReplacementSelectionOnNextParseAfterRecoverSelectionsOnNextParse_SelectionNotSavedPreviously_ModuleOpen()
294338
{
295339
var selectionServiceMock = TestSelectionServiceMock();
296340
var parseManagerMock = new Mock<IParseManager>();
297341
var selectionRecoverer = new SelectionRecoverer(selectionServiceMock.Object, parseManagerMock.Object);
298342

299343
var selectionReplacement = new Selection(22, 2, 44, 5);
300344

301-
selectionRecoverer.SaveSelections(_testModuleSelections
302-
.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
345+
selectionRecoverer.SaveSelections(_testModuleSelections.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
303346
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[2].QualifiedName, selectionReplacement);
304-
selectionRecoverer.RecoverSavedSelections();
347+
selectionRecoverer.RecoverSavedSelectionsOnNextParse();
305348

306-
foreach (var qualifiedSelection in _testModuleSelections.Take(2))
307-
{
308-
selectionServiceMock.Verify(
309-
m => m.TrySetSelection(qualifiedSelection.QualifiedName, qualifiedSelection.Selection), Times.Once);
310-
}
349+
var stateEventArgs = new ParserStateEventArgs(_stateExpectedToTriggerTheRecovery, ParserState.Pending,
350+
CancellationToken.None);
351+
parseManagerMock.Raise(m => m.StateChanged += null, stateEventArgs);
311352

312-
selectionServiceMock.Verify(
313-
m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, selectionReplacement), Times.Once);
353+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, _testModuleSelections[0].Selection), Times.Once);
354+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection), Times.Once);
355+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, selectionReplacement), Times.Once);
356+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[3].QualifiedName, It.IsAny<Selection>()), Times.Never);
357+
}
358+
359+
[Test]
360+
[Category("Rewriting")]
361+
public void DoesNotSaveOrSetReplacementSelectionOnOnNextParseAfterRecoverSelectionsOnNextParse_SelectionNotSavedPreviously_ModuleNotOpen()
362+
{
363+
var selectionServiceMock = TestSelectionServiceMock();
364+
var parseManagerMock = new Mock<IParseManager>();
365+
var selectionRecoverer = new SelectionRecoverer(selectionServiceMock.Object, parseManagerMock.Object);
366+
367+
selectionServiceMock.Setup(m => m.OpenModules())
368+
.Returns(() => _testModuleSelections.Take(2).Select(qs => qs.QualifiedName).ToList());
369+
370+
var selectionReplacement = new Selection(22, 2, 44, 5);
371+
372+
selectionRecoverer.SaveSelections(_testModuleSelections.Select(qualifiedSelection => qualifiedSelection.QualifiedName).Take(2));
373+
selectionRecoverer.ReplaceSavedSelection(_testModuleSelections[2].QualifiedName, selectionReplacement);
374+
selectionRecoverer.RecoverSavedSelectionsOnNextParse();
375+
376+
var stateEventArgs = new ParserStateEventArgs(_stateExpectedToTriggerTheRecovery, ParserState.Pending,
377+
CancellationToken.None);
378+
parseManagerMock.Raise(m => m.StateChanged += null, stateEventArgs);
379+
380+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[0].QualifiedName), Times.Once);
381+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[1].QualifiedName), Times.Once);
382+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[2].QualifiedName), Times.Never);
383+
selectionServiceMock.Verify(m => m.Selection(_testModuleSelections[3].QualifiedName), Times.Never);
384+
385+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[0].QualifiedName, _testModuleSelections[0].Selection), Times.Once);
386+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[1].QualifiedName, _testModuleSelections[1].Selection), Times.Once);
387+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[2].QualifiedName, It.IsAny<Selection>()), Times.Never);
388+
selectionServiceMock.Verify(m => m.TrySetSelection(_testModuleSelections[3].QualifiedName, It.IsAny<Selection>()), Times.Never);
314389
}
315390

316391
[Test]
317392
[Category("Rewriting")]
318-
public void SetsReplacementSelectionOnParseAfterRecoverSelectionsOnNextParse_SelectionNotSavedPreviously()
393+
public void SetsReplacementSelectionOnParseAfterRecoverSelectionsOnNextParse_SelectionSavedPreviously()
319394
{
320395
var selectionServiceMock = TestSelectionServiceMock();
321396
var parseManagerMock = new Mock<IParseManager>();

0 commit comments

Comments
 (0)