Skip to content

Commit f501e89

Browse files
committed
fixes #4621
1 parent c926d73 commit f501e89

File tree

4 files changed

+91
-54
lines changed

4 files changed

+91
-54
lines changed

Rubberduck.Core/AutoComplete/Service/SelfClosingPairHandler.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,38 @@ private bool HandleInternal(AutoCompleteEventArgs e, CodeString original, SelfCl
8484
{
8585
if (!original.CaretPosition.IsSingleCharacter)
8686
{
87-
// todo: WrapSelection?
87+
// todo: WrapSelectionWith(pair)?
8888
result = null;
8989
return false;
9090
}
9191

92-
var isPresent = original.CaretLine.EndsWith($"{pair.OpeningChar}{pair.ClosingChar}");
93-
92+
// if executing the SCP against the original code yields no result, we need to bail out.
9493
if (!_scpService.Execute(pair, original, e.Character, out result))
9594
{
9695
return false;
9796
}
9897

98+
// let the VBE alter the original code if it wants to, then work with the prettified code.
9999
var prettified = CodePaneHandler.Prettify(e.Module, original);
100+
101+
var isPresent = original.CaretLine.EndsWith($"{pair.OpeningChar}{pair.ClosingChar}");
100102
if (!isPresent && original.CaretLine.Length + 2 == prettified.CaretLine.Length &&
101103
prettified.CaretLine.EndsWith($"{pair.OpeningChar}{pair.ClosingChar}"))
102104
{
103105
// prettifier just added the pair for us; likely a Sub or Function statement.
104-
prettified = original; // pretend this didn't happen. note: probably breaks if original has extra whitespace.
106+
prettified = original; // pretend this didn't happen; we need to work out the caret position anyway.
105107
}
106108

109+
if (prettified.CaretLine.Length == 0)
110+
{
111+
// prettifier destroyed the indent. need to reinstate it now.
112+
prettified = prettified.ReplaceLine(
113+
index:prettified.CaretPosition.StartLine,
114+
content:new string(' ', original.CaretLine.TakeWhile(c => c == ' ').Count())
115+
);
116+
}
117+
118+
// if executing the SCP against the prettified code yields no result, we need to bail out.
107119
if (!_scpService.Execute(pair, prettified, e.Character, out result))
108120
{
109121
return false;
@@ -117,7 +129,7 @@ private bool HandleInternal(AutoCompleteEventArgs e, CodeString original, SelfCl
117129
result = null;
118130
return false;
119131
}
120-
132+
121133
var currentLine = reprettified.Lines[reprettified.CaretPosition.StartLine];
122134
if (!string.IsNullOrWhiteSpace(currentLine) &&
123135
currentLine.EndsWith(" ") &&
@@ -130,7 +142,7 @@ private bool HandleInternal(AutoCompleteEventArgs e, CodeString original, SelfCl
130142
e.Character == pair.OpeningChar &&
131143
!result.CaretLine.EndsWith($"{pair.OpeningChar}{pair.ClosingChar}"))
132144
{
133-
// VBE eats it. bail out but still swallow the keypress.
145+
// VBE eats it. bail out but still swallow the keypress; we already prettified the opening character into the editor.
134146
e.Handled = true;
135147
result = null;
136148
return false;

RubberduckTests/AutoComplete/SelfClosingPairHandlerTests.cs

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,9 @@
11
using NUnit.Framework;
2-
using Moq;
32
using Rubberduck.AutoComplete.Service;
4-
using Rubberduck.Settings;
53
using Rubberduck.VBEditor;
6-
using Rubberduck.VBEditor.SourceCodeHandling;
7-
using Rubberduck.VBEditor.Events;
8-
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
94

105
namespace RubberduckTests.AutoComplete
116
{
12-
public class SelfClosingPairTestInfo
13-
{
14-
public SelfClosingPairTestInfo(CodeString original, char input, CodeString rePrettified)
15-
: this(new Mock<SelfClosingPairCompletionService>(), original, original, input, rePrettified) { }
16-
17-
public SelfClosingPairTestInfo(CodeString original, char input)
18-
: this(new Mock<SelfClosingPairCompletionService>(), original, original, input, original) { }
19-
20-
public SelfClosingPairTestInfo(CodeString original, CodeString prettified, char input)
21-
: this(new Mock<SelfClosingPairCompletionService>(), original, prettified, input, prettified) { }
22-
23-
public SelfClosingPairTestInfo(Mock<SelfClosingPairCompletionService> service, CodeString original, CodeString prettified, char input, CodeString rePrettified, bool isControlKeyDown = false, bool isDeleteKey = false)
24-
{
25-
Original = original;
26-
Prettified = prettified;
27-
Input = input;
28-
RePrettified = rePrettified;
29-
Settings = AutoCompleteSettings.AllEnabled;
30-
31-
Service = service;
32-
Module = new Mock<ICodeModule>();
33-
Handler = new Mock<ICodePaneHandler>();
34-
Handler.Setup(e => e.GetCurrentLogicalLine(Module.Object)).Returns(original);
35-
Handler.SetupSequence(e => e.Prettify(Module.Object, It.IsAny<CodeString>()))
36-
.Returns(prettified)
37-
.Returns(rePrettified);
38-
39-
Args = new AutoCompleteEventArgs(Module.Object, input, isControlKeyDown, isDeleteKey);
40-
}
41-
42-
public Mock<ICodeModule> Module { get; set; }
43-
public Mock<SelfClosingPairCompletionService> Service { get; set; }
44-
public Mock<ICodePaneHandler> Handler { get; set; }
45-
public CodeString Original { get; set; }
46-
public CodeString Prettified { get; set; }
47-
public char Input { get; set; }
48-
public CodeString RePrettified { get; set; }
49-
public AutoCompleteEventArgs Args { get; set; }
50-
public AutoCompleteSettings Settings { get; set; }
51-
52-
public TestCodeString Result { get; set; }
53-
}
54-
557
[TestFixture]
568
public class SelfClosingPairHandlerTests
579
{
@@ -114,6 +66,21 @@ public void GivenOpeningParenthesisOnCallStatement_ReturnsFalseAndLetsKeypressTh
11466
Assert.IsFalse(Run(info));
11567
Assert.IsFalse(info.Args.Handled);
11668
}
69+
70+
[Test]
71+
public void GivenOpeningCharInsideMultilineArgumentList_ReturnsTrueAndSwallowsKeypress()
72+
{
73+
var input = '"';
74+
var original = @"Err.Raise 5, _
75+
|".ToCodeString();
76+
var rePrettified = @"Err.Raise 5, _
77+
""|""".ToCodeString();
78+
var info = new SelfClosingPairTestInfo(original, input, rePrettified);
79+
80+
Assert.IsTrue(Run(info));
81+
Assert.IsTrue(info.Args.Handled);
82+
}
83+
11784
[Test]
11885
public void GivenBackspaceOnMatchedPair_DeletesMatchingTokens()
11986
{
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Moq;
2+
using Rubberduck.AutoComplete.Service;
3+
using Rubberduck.Settings;
4+
using Rubberduck.VBEditor;
5+
using Rubberduck.VBEditor.Events;
6+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
7+
using Rubberduck.VBEditor.SourceCodeHandling;
8+
9+
namespace RubberduckTests.AutoComplete
10+
{
11+
public class SelfClosingPairTestInfo
12+
{
13+
public SelfClosingPairTestInfo(CodeString original, char input, CodeString rePrettified)
14+
: this(new Mock<SelfClosingPairCompletionService>(), original, original, input, rePrettified) { }
15+
public SelfClosingPairTestInfo(CodeString original, CodeString prettified, char input, CodeString rePrettified)
16+
: this(new Mock<SelfClosingPairCompletionService>(), original, prettified, input, rePrettified) { }
17+
18+
public SelfClosingPairTestInfo(CodeString original, char input)
19+
: this(new Mock<SelfClosingPairCompletionService>(), original, original, input, original) { }
20+
21+
public SelfClosingPairTestInfo(Mock<SelfClosingPairCompletionService> service,
22+
CodeString original,
23+
CodeString prettified,
24+
char input,
25+
CodeString rePrettified,
26+
bool isControlKeyDown = false,
27+
bool isDeleteKey = false)
28+
{
29+
Original = original;
30+
Prettified = prettified;
31+
Input = input;
32+
RePrettified = rePrettified;
33+
Settings = AutoCompleteSettings.AllEnabled;
34+
35+
Service = service;
36+
Module = new Mock<ICodeModule>();
37+
Handler = new Mock<ICodePaneHandler>();
38+
Handler.Setup(e => e.GetCurrentLogicalLine(Module.Object)).Returns(original);
39+
Handler.SetupSequence(e => e.Prettify(Module.Object, It.IsAny<CodeString>()))
40+
.Returns(prettified)
41+
.Returns(rePrettified);
42+
43+
Args = new AutoCompleteEventArgs(Module.Object, input, isControlKeyDown, isDeleteKey);
44+
}
45+
46+
public Mock<ICodeModule> Module { get; set; }
47+
public Mock<SelfClosingPairCompletionService> Service { get; set; }
48+
public Mock<ICodePaneHandler> Handler { get; set; }
49+
public CodeString Original { get; set; }
50+
public CodeString Prettified { get; set; }
51+
public char Input { get; set; }
52+
public CodeString RePrettified { get; set; }
53+
public AutoCompleteEventArgs Args { get; set; }
54+
public AutoCompleteSettings Settings { get; set; }
55+
56+
public TestCodeString Result { get; set; }
57+
}
58+
}

0 commit comments

Comments
 (0)