Skip to content

Commit a5480c9

Browse files
authored
Merge pull request #4498 from retailcoder/scp
self-closing pair completion bugfix
2 parents 01dcc6a + 35f188f commit a5480c9

11 files changed

+352
-149
lines changed

Rubberduck.Core/AutoComplete/AutoCompleteHandlerBase.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Linq;
3-
using Rubberduck.Parsing.VBA.Extensions;
4-
using Rubberduck.Settings;
1+
using Rubberduck.Settings;
52
using Rubberduck.VBEditor;
63
using Rubberduck.VBEditor.Events;
74
using Rubberduck.VBEditor.SourceCodeHandling;
@@ -17,6 +14,6 @@ protected AutoCompleteHandlerBase(ICodePaneHandler pane)
1714

1815
protected ICodePaneHandler CodePaneHandler { get; }
1916

20-
public abstract CodeString Handle(AutoCompleteEventArgs e, AutoCompleteSettings settings);
17+
public abstract bool Handle(AutoCompleteEventArgs e, AutoCompleteSettings settings, out CodeString result);
2118
}
2219
}

Rubberduck.Core/AutoComplete/Service/AutoCompleteService.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,13 @@ private void HandleKeyDown(object sender, AutoCompleteEventArgs e)
135135

136136
foreach (var handler in _handlers)
137137
{
138-
var result = handler.Handle(e, _settings);
139-
if (result != null && e.Handled)
138+
if (!handler.Handle(e, _settings, out _))
140139
{
141-
return;
140+
continue;
142141
}
142+
143+
e.Handled = true;
144+
return;
143145
}
144146
}
145147

Rubberduck.Core/AutoComplete/Service/SelfClosingPair.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1-
namespace Rubberduck.AutoComplete.Service
1+
using Rubberduck.VBEditor;
2+
using System;
3+
4+
namespace Rubberduck.AutoComplete.Service
25
{
3-
public class SelfClosingPair
6+
public class SelfClosingPair : IEquatable<SelfClosingPair>
47
{
8+
[Flags]
9+
public enum MatchType
10+
{
11+
NoMatch = 0,
12+
OpeningCharacterMatch = 1,
13+
ClosingCharacterMatch = 2,
14+
}
15+
516
public SelfClosingPair(char opening, char closing)
617
{
718
OpeningChar = opening;
@@ -15,5 +26,15 @@ public SelfClosingPair(char opening, char closing)
1526
/// True if <see cref="OpeningChar"/> is the same as <see cref="ClosingChar"/>.
1627
/// </summary>
1728
public bool IsSymetric => OpeningChar == ClosingChar;
29+
30+
public bool Equals(SelfClosingPair other) => other?.OpeningChar == OpeningChar &&
31+
other.ClosingChar == ClosingChar;
32+
33+
public override bool Equals(object obj)
34+
{
35+
return obj is SelfClosingPair scp && Equals(scp);
36+
}
37+
38+
public override int GetHashCode() => HashCode.Compute(OpeningChar, ClosingChar);
1839
}
1940
}

Rubberduck.Core/AutoComplete/Service/SelfClosingPairCompletionService.cs

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,25 @@ namespace Rubberduck.AutoComplete.Service
1212
{
1313
public class SelfClosingPairCompletionService
1414
{
15+
/*
16+
// note: this works... but the VBE makes an annoying DING! when the command isn't available.
17+
// todo: implement our own intellisense, then uncomment this code.
1518
private readonly IShowIntelliSenseCommand _showIntelliSense;
1619
1720
public SelfClosingPairCompletionService(IShowIntelliSenseCommand showIntelliSense)
1821
{
1922
_showIntelliSense = showIntelliSense;
2023
}
24+
*/
2125

22-
public CodeString Execute(SelfClosingPair pair, CodeString original, char input)
26+
public bool Execute(SelfClosingPair pair, CodeString original, char input, out CodeString result)
2327
{
28+
result = null;
29+
2430
var previousCharIsClosingChar =
2531
original.CaretPosition.StartColumn > 0 &&
2632
original.CaretLine[original.CaretPosition.StartColumn - 1] == pair.ClosingChar;
33+
2734
var nextCharIsClosingChar =
2835
original.CaretPosition.StartColumn < original.CaretLine.Length &&
2936
original.CaretLine[original.CaretPosition.StartColumn] == pair.ClosingChar;
@@ -33,49 +40,45 @@ public CodeString Execute(SelfClosingPair pair, CodeString original, char input)
3340
previousCharIsClosingChar && !nextCharIsClosingChar
3441
|| original.IsComment || (original.IsInsideStringLiteral && !nextCharIsClosingChar))
3542
{
36-
return null;
43+
return false;
3744
}
3845

3946
if (input == pair.OpeningChar)
4047
{
41-
var result = HandleOpeningChar(pair, original);
42-
return result;
48+
return HandleOpeningChar(pair, original, out result);
4349
}
44-
50+
4551
if (input == pair.ClosingChar)
4652
{
47-
return HandleClosingChar(pair, original);
53+
return HandleClosingChar(pair, original, out result);
4854
}
4955

5056
if (input == '\b')
5157
{
52-
return Execute(pair, original, Keys.Back);
58+
return Execute(pair, original, Keys.Back, out result);
5359
}
5460

55-
return null;
61+
return false;
5662
}
5763

58-
public CodeString Execute(SelfClosingPair pair, CodeString original, Keys input)
64+
public bool Execute(SelfClosingPair pair, CodeString original, Keys input, out CodeString result)
5965
{
66+
result = null;
6067
if (original.IsComment)
6168
{
62-
return null;
69+
// not handling backspace in comments
70+
return false;
6371
}
6472

65-
if (input == Keys.Back)
66-
{
67-
return HandleBackspace(pair, original);
68-
}
69-
70-
return null;
73+
return input == Keys.Back && HandleBackspace(pair, original, out result);
7174
}
7275

73-
private CodeString HandleOpeningChar(SelfClosingPair pair, CodeString original)
76+
private bool HandleOpeningChar(SelfClosingPair pair, CodeString original, out CodeString result)
7477
{
7578
var nextPosition = original.CaretPosition.ShiftRight();
7679
var autoCode = new string(new[] { pair.OpeningChar, pair.ClosingChar });
7780
var lines = original.Lines;
78-
var line = lines[original.CaretPosition.StartLine];
81+
var line = original.CaretLine;
7982

8083
string newCode;
8184
if (string.IsNullOrEmpty(line))
@@ -94,14 +97,17 @@ private CodeString HandleOpeningChar(SelfClosingPair pair, CodeString original)
9497
}
9598
lines[original.CaretPosition.StartLine] = newCode;
9699

97-
return new CodeString(string.Join("\r\n", lines), nextPosition, new Selection(original.SnippetPosition.StartLine, 1, original.SnippetPosition.EndLine, 1));
100+
result = new CodeString(string.Join("\r\n", lines), nextPosition, new Selection(original.SnippetPosition.StartLine, 1, original.SnippetPosition.EndLine, 1));
101+
return true;
98102
}
99103

100-
private CodeString HandleClosingChar(SelfClosingPair pair, CodeString original)
104+
private bool HandleClosingChar(SelfClosingPair pair, CodeString original, out CodeString result)
101105
{
106+
result = null;
102107
if (pair.IsSymetric)
103108
{
104-
return null;
109+
// a symetric pair would have already been handled with the opening character.
110+
return false;
105111
}
106112

107113
var nextIsClosingChar = original.CaretLine.Length > original.CaretCharIndex &&
@@ -111,26 +117,24 @@ private CodeString HandleClosingChar(SelfClosingPair pair, CodeString original)
111117
var nextPosition = original.CaretPosition.ShiftRight();
112118
var newCode = original.Code;
113119

114-
return new CodeString(newCode, nextPosition, new Selection(original.SnippetPosition.StartLine, 1, original.SnippetPosition.EndLine, 1));
120+
result = new CodeString(newCode, nextPosition, new Selection(original.SnippetPosition.StartLine, 1, original.SnippetPosition.EndLine, 1));
121+
return true;
115122
}
116-
return null;
117-
}
118123

119-
private CodeString HandleBackspace(SelfClosingPair pair, CodeString original)
120-
{
121-
return DeleteMatchingTokens(pair, original);
124+
return false;
122125
}
123126

124-
private CodeString DeleteMatchingTokens(SelfClosingPair pair, CodeString original)
127+
private bool HandleBackspace(SelfClosingPair pair, CodeString original, out CodeString result)
125128
{
129+
result = null;
126130
var position = original.CaretPosition;
127131
var lines = original.Lines;
128132

129133
var line = lines[original.CaretPosition.StartLine];
130134
if (line.Length == 0)
131135
{
132136
// nothing to delete at caret position... bail out.
133-
return null;
137+
return false;
134138
}
135139

136140
var previous = Math.Max(0, position.StartColumn - 1);
@@ -146,24 +150,25 @@ private CodeString DeleteMatchingTokens(SelfClosingPair pair, CodeString origina
146150
if (line.Length == 2)
147151
{
148152
// entire line consists in the self-closing pair itself.
149-
return new CodeString(string.Empty, default, Selection.Empty.ShiftRight());
153+
result = new CodeString(string.Empty, default, Selection.Empty.ShiftRight());
150154
}
151155

152156
// simple case; caret is between the opening and closing chars - remove both.
153157
lines[original.CaretPosition.StartLine] = line.Remove(previous, 2);
154-
return new CodeString(string.Join("\r\n", lines), original.CaretPosition.ShiftLeft(), original.SnippetPosition);
158+
result = new CodeString(string.Join("\r\n", lines), original.CaretPosition.ShiftLeft(), original.SnippetPosition);
155159
}
156160

157161
if (previous < line.Length - 1 && previousChar == pair.OpeningChar)
158162
{
159-
return DeleteMatchingTokensMultiline(pair, original);
163+
return DeleteMatchingTokensMultiline(pair, original, out result);
160164
}
161165

162-
return null;
166+
return result != null;
163167
}
164168

165-
private CodeString DeleteMatchingTokensMultiline(SelfClosingPair pair, CodeString original)
169+
private bool DeleteMatchingTokensMultiline(SelfClosingPair pair, CodeString original, out CodeString result)
166170
{
171+
result = null;
167172
var position = original.CaretPosition;
168173
var lines = original.Lines;
169174
var line = lines[original.CaretPosition.StartLine];
@@ -177,7 +182,7 @@ private CodeString DeleteMatchingTokensMultiline(SelfClosingPair pair, CodeStrin
177182
if (closingTokenPosition == default)
178183
{
179184
// could not locate the closing token... bail out.
180-
return null;
185+
return false;
181186
}
182187

183188
var closingLine = lines[closingTokenPosition.EndLine].Remove(closingTokenPosition.StartColumn, 1);
@@ -243,8 +248,9 @@ private CodeString DeleteMatchingTokensMultiline(SelfClosingPair pair, CodeStrin
243248
// remove any dangling empty lines...
244249
lines = lines.Where((x, i) => i <= position.StartLine || !string.IsNullOrWhiteSpace(x)).ToArray();
245250

246-
return new CodeString(string.Join("\r\n", lines), finalCaretPosition,
251+
result = new CodeString(string.Join("\r\n", lines), finalCaretPosition,
247252
new Selection(original.SnippetPosition.StartLine, 1, original.SnippetPosition.EndLine, 1));
253+
return true;
248254
}
249255

250256
private static Selection HandleBackspaceContinuations(string[] nonEmptyLines, Selection finalCaretPosition)

0 commit comments

Comments
 (0)