Skip to content

Commit 55ba210

Browse files
committed
Wire up selection recovery in the RewriteSessionBase
1 parent bdc3169 commit 55ba210

File tree

8 files changed

+158
-17
lines changed

8 files changed

+158
-17
lines changed

Rubberduck.Parsing/Rewriter/AttributesRewriteSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ public class AttributesRewriteSession : RewriteSessionBase
99
{
1010
private readonly IParseManager _parseManager;
1111

12-
public AttributesRewriteSession(IParseManager parseManager, IRewriterProvider rewriterProvider,
12+
public AttributesRewriteSession(IParseManager parseManager, IRewriterProvider rewriterProvider, ISelectionRecoverer selectionRecoverer,
1313
Func<IRewriteSession, bool> rewritingAllowed)
14-
: base(rewriterProvider, rewritingAllowed)
14+
: base(rewriterProvider, selectionRecoverer, rewritingAllowed)
1515
{
1616
_parseManager = parseManager;
1717
}

Rubberduck.Parsing/Rewriter/CodePaneRewriteSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ public class CodePaneRewriteSession : RewriteSessionBase
99
{
1010
private readonly IParseManager _parseManager;
1111

12-
public CodePaneRewriteSession(IParseManager parseManager, IRewriterProvider rewriterProvider,
12+
public CodePaneRewriteSession(IParseManager parseManager, IRewriterProvider rewriterProvider, ISelectionRecoverer selectionRecoverer,
1313
Func<IRewriteSession, bool> rewritingAllowed)
14-
: base(rewriterProvider, rewritingAllowed)
14+
: base(rewriterProvider, selectionRecoverer, rewritingAllowed)
1515
{
1616
_parseManager = parseManager;
1717
}

Rubberduck.Parsing/Rewriter/RewriteSessionBase.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,28 @@
55
using Rubberduck.Parsing.VBA.Extensions;
66
using Rubberduck.Parsing.VBA.Parsing;
77
using Rubberduck.VBEditor;
8+
using Rubberduck.VBEditor.Extensions;
89

910
namespace Rubberduck.Parsing.Rewriter
1011
{
1112
public abstract class RewriteSessionBase : IRewriteSession
1213
{
1314
protected readonly IDictionary<QualifiedModuleName, IExecutableModuleRewriter> CheckedOutModuleRewriters = new Dictionary<QualifiedModuleName, IExecutableModuleRewriter>();
14-
protected readonly IRewriterProvider RewriterProvider;
15+
protected readonly IRewriterProvider RewriterProvider;
1516

17+
private readonly ISelectionRecoverer _selectionRecoverer;
1618
private readonly Func<IRewriteSession, bool> _rewritingAllowed;
1719

1820
protected readonly Logger Logger = LogManager.GetCurrentClassLogger();
1921
private readonly object _statusLockObject = new object();
2022

2123
public abstract CodeKind TargetCodeKind { get; }
2224

23-
protected RewriteSessionBase(IRewriterProvider rewriterProvider, Func<IRewriteSession, bool> rewritingAllowed)
25+
protected RewriteSessionBase(IRewriterProvider rewriterProvider, ISelectionRecoverer selectionRecoverer, Func<IRewriteSession, bool> rewritingAllowed)
2426
{
2527
RewriterProvider = rewriterProvider;
2628
_rewritingAllowed = rewritingAllowed;
29+
_selectionRecoverer = selectionRecoverer;
2730
}
2831

2932
public IReadOnlyCollection<QualifiedModuleName> CheckedOutModules => CheckedOutModuleRewriters.Keys.ToHashSet();
@@ -91,9 +94,30 @@ public bool TryRewrite()
9194
return false;
9295
}
9396

97+
PrimeSelectionRecovery();
98+
9499
return TryRewriteInternal();
95100
}
96101

97102
protected abstract bool TryRewriteInternal();
103+
104+
private void PrimeSelectionRecovery()
105+
{
106+
_selectionRecoverer.SaveSelections(CheckedOutModuleRewriters.Keys);
107+
108+
foreach (var (module, rewriter) in CheckedOutModuleRewriters)
109+
{
110+
if (rewriter.SelectionOffset.HasValue)
111+
{
112+
_selectionRecoverer.AdjustSavedSelection(module, rewriter.SelectionOffset.Value);
113+
}
114+
if (rewriter.Selection.HasValue)
115+
{
116+
_selectionRecoverer.ReplaceSavedSelection(module, rewriter.Selection.Value);
117+
}
118+
}
119+
120+
_selectionRecoverer.RecoverSavedSelectionsOnNextParse();
121+
}
98122
}
99123
}

Rubberduck.Parsing/Rewriter/RewriteSessionFactory.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@ public class RewriteSessionFactory : IRewriteSessionFactory
77
{
88
private readonly RubberduckParserState _state;
99
private readonly IRewriterProvider _rewriterProvider;
10+
private readonly ISelectionRecoverer _selectionRecoverer;
1011

11-
public RewriteSessionFactory(RubberduckParserState state, IRewriterProvider rewriterProvider)
12+
public RewriteSessionFactory(RubberduckParserState state, IRewriterProvider rewriterProvider, ISelectionRecoverer selectionRecoverer)
1213
{
1314
_state = state;
1415
_rewriterProvider = rewriterProvider;
16+
_selectionRecoverer = selectionRecoverer;
1517
}
1618

1719
public IRewriteSession CodePaneSession(Func<IRewriteSession, bool> rewritingAllowed)
1820
{
19-
return new CodePaneRewriteSession(_state, _rewriterProvider, rewritingAllowed);
21+
return new CodePaneRewriteSession(_state, _rewriterProvider, _selectionRecoverer, rewritingAllowed);
2022
}
2123

2224
public IRewriteSession AttributesSession(Func<IRewriteSession, bool> rewritingAllowed)
2325
{
24-
return new AttributesRewriteSession(_state, _rewriterProvider, rewritingAllowed);
26+
return new AttributesRewriteSession(_state, _rewriterProvider, _selectionRecoverer, rewritingAllowed);
2527
}
2628
}
2729
}

RubberduckTests/Mocks/MockParser.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using Rubberduck.VBEditor.Events;
2525
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
2626
using Rubberduck.VBEditor.SourceCodeHandling;
27+
using Rubberduck.VBEditor.Utility;
2728

2829
namespace RubberduckTests.Mocks
2930
{
@@ -133,7 +134,9 @@ public static (SynchronousParseCoordinator parser, IRewritingManager rewritingMa
133134
codePaneSourceCodeHandler,
134135
attributesSourceCodeHandler);
135136
var rewriterProvider = new RewriterProvider(tokenStreamCache, moduleRewriterFactory);
136-
var rewriteSessionFactory = new RewriteSessionFactory(state, rewriterProvider);
137+
var selectionService = new SelectionService(vbe, projectRepository);
138+
var selectionRecoverer = new SelectionRecoverer(selectionService, state);
139+
var rewriteSessionFactory = new RewriteSessionFactory(state, rewriterProvider, selectionRecoverer);
137140
var stubMembersAttributeRecoverer = new Mock<IMemberAttributeRecovererWithSettableRewritingManager>().Object;
138141
var rewritingManager = new RewritingManager(rewriteSessionFactory, stubMembersAttributeRecoverer);
139142

RubberduckTests/Rewriter/AttributesRewriteSessionTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,14 @@ public void TargetsAttributesCode()
8989
Assert.AreEqual(CodeKind.AttributesCode, rewriteSession.TargetCodeKind);
9090
}
9191

92-
protected override IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false)
92+
protected override IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false, ISelectionRecoverer selectionRecoverer = null)
9393
{
94+
if (selectionRecoverer == null)
95+
{
96+
selectionRecoverer = new Mock<ISelectionRecoverer>().Object;
97+
}
9498
mockProvider = new MockRewriterProvider(rewritersAreDirty);
95-
return new AttributesRewriteSession(parseManager, mockProvider, rewritingAllowed);
99+
return new AttributesRewriteSession(parseManager, mockProvider, selectionRecoverer, rewritingAllowed);
96100
}
97101
}
98102
}

RubberduckTests/Rewriter/CodePaneRewriteSessionTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,14 @@ public void TargetsCodePaneCode()
9898
Assert.AreEqual(CodeKind.CodePaneCode, rewriteSession.TargetCodeKind);
9999
}
100100

101-
protected override IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false)
101+
protected override IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false, ISelectionRecoverer selectionRecoverer = null)
102102
{
103+
if (selectionRecoverer == null)
104+
{
105+
selectionRecoverer = new Mock<ISelectionRecoverer>().Object;
106+
}
103107
mockProvider = new MockRewriterProvider(rewritersAreDirty);
104-
return new CodePaneRewriteSession(parseManager, mockProvider, rewritingAllowed);
108+
return new CodePaneRewriteSession(parseManager, mockProvider, selectionRecoverer, rewritingAllowed);
105109
}
106110
}
107111
}

RubberduckTests/Rewriter/RewriteSessionTestBase.cs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,17 +249,119 @@ public void ChecksOutRewritersForTheTargetCodeKind()
249249
Assert.AreEqual(expectedCodeKind, actualCodeKind);
250250
}
251251

252+
[Test]
253+
[Category("Rewriter")]
254+
public void CallsRecoverSelectionOnNextParseOnRewrite()
255+
{
256+
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
257+
selectionRecovererMock.Setup(m => m.RecoverSavedSelectionsOnNextParse());
258+
259+
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
260+
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
261+
262+
rewriteSession.CheckOutModuleRewriter(module);
263+
rewriteSession.TryRewrite();
264+
265+
selectionRecovererMock.Verify(m => m.RecoverSavedSelectionsOnNextParse(), Times.Once);
266+
}
267+
268+
[Test]
269+
[Category("Rewriter")]
270+
public void SavesSelectionForCheckedOutModulesOnRewrite()
271+
{
272+
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
273+
selectionRecovererMock.Setup(m => m.SaveSelections(It.IsAny<IEnumerable<QualifiedModuleName>>()));
274+
275+
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
276+
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
277+
var module2 = new QualifiedModuleName("TestProject", string.Empty, "TestModule2");
278+
279+
rewriteSession.CheckOutModuleRewriter(module);
280+
rewriteSession.CheckOutModuleRewriter(module2);
281+
rewriteSession.TryRewrite();
282+
283+
selectionRecovererMock.Verify(m => m.SaveSelections(It.Is<IEnumerable<QualifiedModuleName>>(modules => modules.Count() == 2 && modules.Contains(module) && modules.Contains(module2))));
284+
}
285+
286+
[Test]
287+
[Category("Rewriter")]
288+
public void AdjustsSelectionForCheckedOutModulesOnRewriteWhoseRewriterHasASelectionOffsetSet()
289+
{
290+
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
291+
selectionRecovererMock.Setup(m => m.AdjustSavedSelection(It.IsAny<QualifiedModuleName>(), It.IsAny<Selection>()));
292+
293+
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
294+
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
295+
var module2 = new QualifiedModuleName("TestProject", string.Empty, "TestModule2");
296+
297+
var selectionOffset = new Selection(2,3);
298+
299+
var rewriter = rewriteSession.CheckOutModuleRewriter(module);
300+
rewriter.SelectionOffset = selectionOffset;
301+
rewriteSession.CheckOutModuleRewriter(module2);
302+
rewriteSession.TryRewrite();
303+
304+
selectionRecovererMock.Verify(m => m.AdjustSavedSelection(module, selectionOffset), Times.Once);
305+
selectionRecovererMock.Verify(m => m.AdjustSavedSelection(module2, It.IsAny<Selection>()), Times.Never);
306+
}
307+
308+
[Test]
309+
[Category("Rewriter")]
310+
public void ReplacesSelectionForCheckedOutModulesOnRewriteWhoseRewriterHasASelectionSet()
311+
{
312+
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
313+
var moduleSelection = new Selection(4,3);
314+
selectionRecovererMock.Setup(m => m.ReplaceSavedSelection(It.IsAny<QualifiedModuleName>(), It.IsAny<Selection>())).Callback((QualifiedModuleName qmn, Selection selection) => moduleSelection = selection);
315+
selectionRecovererMock.Setup(m => m.AdjustSavedSelection(It.IsAny<QualifiedModuleName>(), It.IsAny<Selection>())).Callback((QualifiedModuleName qmn, Selection selection) => moduleSelection = moduleSelection.Offset(selection));
316+
317+
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
318+
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
319+
320+
var selectionReplacement = new Selection(2, 3);
321+
var selectionOffset = new Selection(42,42);
322+
323+
var rewriter = rewriteSession.CheckOutModuleRewriter(module);
324+
rewriter.Selection = selectionReplacement;
325+
rewriter.SelectionOffset = selectionOffset;
326+
rewriteSession.TryRewrite();
327+
328+
Assert.AreEqual(selectionReplacement, moduleSelection);
329+
}
330+
331+
[Test]
332+
[Category("Rewriter")]
333+
public void FirstAppliesOffsetAndThenReplacesSelectionForCheckedOutModulesOnRewriteWhoseRewriterHasASelectionAndASelectionOffsetSet()
334+
{
335+
var selectionRecovererMock = new Mock<ISelectionRecoverer>();
336+
selectionRecovererMock.Setup(m => m.ReplaceSavedSelection(It.IsAny<QualifiedModuleName>(), It.IsAny<Selection>()));
337+
338+
var rewriteSession = RewriteSession(session => true, out var mockRewriterProvider, selectionRecoverer: selectionRecovererMock.Object);
339+
var module = new QualifiedModuleName("TestProject", string.Empty, "TestModule");
340+
var module2 = new QualifiedModuleName("TestProject", string.Empty, "TestModule2");
341+
342+
var selectionReplacement = new Selection(2, 3);
343+
344+
var rewriter = rewriteSession.CheckOutModuleRewriter(module);
345+
rewriter.Selection = selectionReplacement;
346+
rewriteSession.CheckOutModuleRewriter(module2);
347+
rewriteSession.TryRewrite();
348+
349+
selectionRecovererMock.Verify(m => m.ReplaceSavedSelection(module, selectionReplacement), Times.Once);
350+
selectionRecovererMock.Verify(m => m.ReplaceSavedSelection(module2, It.IsAny<Selection>()), Times.Never);
351+
}
352+
353+
252354
protected IRewriteSession RewriteSession(Func<IRewriteSession, bool> rewritingAllowed,
253-
out MockRewriterProvider mockProvider, bool rewritersAreDirty = false)
355+
out MockRewriterProvider mockProvider, bool rewritersAreDirty = false, ISelectionRecoverer selectionRecoverer = null)
254356
{
255357
var parseManager = new Mock<IParseManager>();
256358
parseManager.Setup(m => m.OnSuspendParser(It.IsAny<object>(), It.IsAny<IEnumerable<ParserState>>(), It.IsAny<Action>(), It.IsAny<int>()))
257359
.Callback((object requestor, IEnumerable<ParserState> allowedStates, Action suspendAction, int timeout) => suspendAction())
258360
.Returns((object requestor, IEnumerable<ParserState> allowedStates, Action suspendAction, int timeout) => SuspensionResult.Completed);
259-
return RewriteSession(parseManager.Object, rewritingAllowed, out mockProvider, rewritersAreDirty);
361+
return RewriteSession(parseManager.Object, rewritingAllowed, out mockProvider, rewritersAreDirty, selectionRecoverer);
260362
}
261363

262-
protected abstract IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false);
364+
protected abstract IRewriteSession RewriteSession(IParseManager parseManager, Func<IRewriteSession, bool> rewritingAllowed, out MockRewriterProvider mockProvider, bool rewritersAreDirty = false, ISelectionRecoverer selectionRecoverer = null);
263365
}
264366

265367

@@ -286,6 +388,8 @@ private Mock<IExecutableModuleRewriter> CreateMockModuleRewriter()
286388
var mock = new Mock<IExecutableModuleRewriter>();
287389
mock.Setup(m => m.Rewrite());
288390
mock.Setup(m => m.IsDirty).Returns(_createdRewritersAreDirty);
391+
mock.SetupProperty(m => m.SelectionOffset);
392+
mock.SetupProperty(m => m.Selection);
289393

290394
return mock;
291395
}

0 commit comments

Comments
 (0)