Skip to content

Commit 743ed6d

Browse files
committed
Merge branch 'rubberduck-vba/next' into UnreachableCaseInsp_Comments2
2 parents 003bce2 + f3f026d commit 743ed6d

File tree

16 files changed

+347
-25
lines changed

16 files changed

+347
-25
lines changed

Rubberduck.Core/AutoComplete/AutoCompleteService.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Windows.Forms;
5+
using Rubberduck.Parsing.VBA;
56
using Rubberduck.Settings;
67
using Rubberduck.VBEditor;
78
using Rubberduck.VBEditor.Events;
@@ -56,34 +57,46 @@ private void HandleKeyDown(object sender, AutoCompleteEventArgs e)
5657
{
5758
var module = e.CodeModule;
5859
var qualifiedSelection = module.GetQualifiedSelection();
59-
var selection = qualifiedSelection.Value.Selection;
60+
var pSelection = qualifiedSelection.Value.Selection;
6061

61-
if (_popupShown || (e.Keys != Keys.None && selection.LineCount > 1))
62+
if (_popupShown || (e.Keys != Keys.None && pSelection.LineCount > 1))
6263
{
6364
return;
6465
}
6566

66-
var currentContent = module.GetLines(selection);
67+
var currentContent = module.GetLines(pSelection);
68+
if (e.Keys == Keys.Enter && _settings.EnableSmartConcat && IsInsideStringLiteral(pSelection, ref currentContent))
69+
{
70+
var indent = currentContent.NthIndexOf('"', 1);
71+
var whitespace = new string(' ', indent);
72+
var newCode = $"{currentContent} & _\r\n{whitespace}\"";
73+
module.ReplaceLine(pSelection.StartLine, newCode);
74+
using (var pane = module.CodePane)
75+
{
76+
pane.Selection = new Selection(pSelection.StartLine + 1, indent + 2);
77+
e.Handled = true;
78+
}
79+
}
6780

68-
var handleDelete = e.Keys == Keys.Delete && selection.EndColumn <= currentContent.Length;
69-
var handleBackspace = e.Keys == Keys.Back && selection.StartColumn > 1;
70-
var handleTab = e.Keys == Keys.Tab && !selection.IsSingleCharacter;
71-
var handleEnter = e.Keys == Keys.Enter && !selection.IsSingleCharacter;
81+
var handleDelete = e.Keys == Keys.Delete && pSelection.EndColumn <= currentContent.Length;
82+
var handleBackspace = e.Keys == Keys.Back && pSelection.StartColumn > 1;
83+
var handleTab = e.Keys == Keys.Tab && !pSelection.IsSingleCharacter;
84+
var handleEnter = e.Keys == Keys.Enter && !pSelection.IsSingleCharacter;
7285

7386
foreach (var autoComplete in _autoCompletes.Where(auto => auto.IsEnabled))
7487
{
7588
if ((handleTab || handleEnter) && autoComplete.IsMatch(currentContent))
7689
{
7790
using (var pane = module.CodePane)
7891
{
79-
if (!string.IsNullOrWhiteSpace(module.GetLines(selection.StartLine + 1, 1)))
92+
if (!string.IsNullOrWhiteSpace(module.GetLines(pSelection.StartLine + 1, 1)))
8093
{
81-
module.InsertLines(selection.StartLine + 1, string.Empty);
94+
module.InsertLines(pSelection.StartLine + 1, string.Empty);
8295
e.Handled = e.Keys != Keys.Tab; // swallow ENTER, let TAB through
8396
}
8497
else
8598
{
86-
pane.Selection = new Selection(selection.StartLine + 1, selection.EndColumn);
99+
pane.Selection = new Selection(pSelection.StartLine + 1, pSelection.EndColumn);
87100
e.Handled = true; // base.Execute added the indentation as applicable already.
88101
}
89102
break;
@@ -106,6 +119,28 @@ private void HandleKeyDown(object sender, AutoCompleteEventArgs e)
106119
}
107120
}
108121

122+
private bool IsInsideStringLiteral(Selection pSelection, ref string currentContent)
123+
{
124+
if (!currentContent.Contains("\"") || currentContent.StripStringLiterals().HasComment(out _))
125+
{
126+
return false;
127+
}
128+
129+
var zSelection = pSelection.ToZeroBased();
130+
var leftOfCaret = currentContent.Substring(0, zSelection.StartColumn);
131+
var rightOfCaret = currentContent.Substring(Math.Min(zSelection.StartColumn + 1, currentContent.Length - 1));
132+
if (!rightOfCaret.Contains("\""))
133+
{
134+
// the string isn't terminated, but VBE would terminate it here.
135+
currentContent += "\"";
136+
rightOfCaret += "\"";
137+
}
138+
139+
// odd number of double quotes on either side of the caret means we're inside a string literal, right?
140+
return (leftOfCaret.Count(c => c.Equals('"')) % 2) != 0 &&
141+
(rightOfCaret.Count(c => c.Equals('"')) % 2) != 0;
142+
}
143+
109144
private bool DeleteAroundCaret(AutoCompleteEventArgs e, IAutoComplete autoComplete)
110145
{
111146
if (autoComplete.IsInlineCharCompletion)

Rubberduck.Core/Properties/Settings.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Core/Properties/Settings.settings

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@
259259
</Setting>
260260
<Setting Name="AutoCompleteSettings" Type="Rubberduck.Settings.AutoCompleteSettings" Scope="Application">
261261
<Value Profile="(Default)">&lt;?xml version="1.0" encoding="utf-16"?&gt;
262-
&lt;AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CompleteBlockOnTab="true" CompleteBlockOnEnter="true"&gt;
262+
&lt;AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CompleteBlockOnTab="true" CompleteBlockOnEnter="true" EnableSmartConcat="true"&gt;
263263
&lt;AutoCompletes&gt;
264264
&lt;AutoComplete Key="AutoCompleteClosingBrace" IsEnabled="true" /&gt;
265265
&lt;AutoComplete Key="AutoCompleteClosingBracket" IsEnabled="true" /&gt;
@@ -282,4 +282,4 @@
282282
&lt;/AutoCompleteSettings&gt;</Value>
283283
</Setting>
284284
</Settings>
285-
</SettingsFile>
285+
</SettingsFile>

Rubberduck.Core/Settings/AutoCompleteSettings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public class AutoCompleteSettings : IAutoCompleteSettings, IEquatable<AutoComple
2626
[XmlAttribute]
2727
public bool CompleteBlockOnEnter { get; set; }
2828

29+
[XmlAttribute]
30+
public bool EnableSmartConcat { get; set; }
31+
2932
public AutoCompleteSettings() : this(Enumerable.Empty<AutoCompleteSetting>())
3033
{
3134
/* default constructor required for XML serialization */

Rubberduck.Core/UI/Settings/AutoCompleteSettings.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,11 @@
8484
</StackPanel>
8585
</DockPanel>
8686
</Label>
87-
<DockPanel HorizontalAlignment="Stretch">
87+
<WrapPanel HorizontalAlignment="Center">
8888
<CheckBox Margin="10,10" IsChecked="{Binding CompleteBlockOnTab}" HorizontalAlignment="Center" Content="{Resx ResxName=Rubberduck.Resources.Settings.AutoCompletesPage, Key=HandleTabKey}" />
8989
<CheckBox Margin="10,10" IsChecked="{Binding CompleteBlockOnEnter}" HorizontalAlignment="Center" Content="{Resx ResxName=Rubberduck.Resources.Settings.AutoCompletesPage, Key=HandleEnterKey}" />
90-
</DockPanel>
90+
<CheckBox Margin="10,10" IsChecked="{Binding EnableSmartConcat}" HorizontalAlignment="Center" Content="{Resx ResxName=Rubberduck.Resources.Settings.AutoCompletesPage, Key=EnableSmartConcat}" />
91+
</WrapPanel>
9192
<Border BorderBrush="DarkGray" BorderThickness="1" CornerRadius="2">
9293
<DataGrid Name="AutoCompleteSettingsGrid"
9394
ItemsSource="{Binding Settings}"

Rubberduck.Core/UI/Settings/AutoCompleteSettingsViewModel.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public AutoCompleteSettingsViewModel(Configuration config)
1717
Settings = new ObservableCollection<AutoCompleteSetting>(config.UserSettings.AutoCompleteSettings.AutoCompletes);
1818
CompleteBlockOnEnter = config.UserSettings.AutoCompleteSettings.CompleteBlockOnEnter;
1919
CompleteBlockOnTab = config.UserSettings.AutoCompleteSettings.CompleteBlockOnTab;
20+
EnableSmartConcat = config.UserSettings.AutoCompleteSettings.EnableSmartConcat;
2021

2122
ExportButtonCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), _ => ExportSettings());
2223
ImportButtonCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), _ => ImportSettings());
@@ -45,13 +46,15 @@ public void UpdateConfig(Configuration config)
4546
{
4647
config.UserSettings.AutoCompleteSettings.CompleteBlockOnTab = CompleteBlockOnTab;
4748
config.UserSettings.AutoCompleteSettings.CompleteBlockOnEnter = CompleteBlockOnEnter;
49+
config.UserSettings.AutoCompleteSettings.EnableSmartConcat = EnableSmartConcat;
4850
config.UserSettings.AutoCompleteSettings.AutoCompletes = new HashSet<AutoCompleteSetting>(_settings);
4951
}
5052

5153
private void TransferSettingsToView(Rubberduck.Settings.AutoCompleteSettings toLoad)
5254
{
5355
CompleteBlockOnTab = toLoad.CompleteBlockOnTab;
5456
CompleteBlockOnEnter = toLoad.CompleteBlockOnEnter;
57+
EnableSmartConcat = toLoad.EnableSmartConcat;
5558
Settings = new ObservableCollection<AutoCompleteSetting>(toLoad.AutoCompletes);
5659
}
5760

@@ -73,7 +76,21 @@ public bool CompleteBlockOnTab
7376
}
7477
}
7578
}
76-
79+
80+
private bool _enableSmartConcat;
81+
public bool EnableSmartConcat
82+
{
83+
get { return _enableSmartConcat; }
84+
set
85+
{
86+
if (_enableSmartConcat != value)
87+
{
88+
_enableSmartConcat = value;
89+
OnPropertyChanged();
90+
}
91+
}
92+
}
93+
7794
private bool _completeBlockOnEnter;
7895
public bool CompleteBlockOnEnter
7996
{

Rubberduck.Core/app.config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@
378378
<setting name="AutoCompleteSettings" serializeAs="Xml">
379379
<value>
380380
<AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
381-
xmlns:xsd="http://www.w3.org/2001/XMLSchema" CompleteBlockOnTab="true" CompleteBlockOnEnter="true">
381+
xmlns:xsd="http://www.w3.org/2001/XMLSchema" CompleteBlockOnTab="true"
382+
CompleteBlockOnEnter="true" EnableSmartConcat="true">
382383
<AutoCompletes>
383384
<AutoComplete Key="AutoCompleteClosingBrace" IsEnabled="true" />
384385
<AutoComplete Key="AutoCompleteClosingBracket" IsEnabled="true" />

Rubberduck.Parsing/Grammar/VBALexer.g4

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ POW : '^';
242242
RPAREN : ')';
243243
L_SQUARE_BRACKET : '[';
244244
R_SQUARE_BRACKET : ']';
245+
L_BRACE : '{';
246+
R_BRACE : '}';
245247
STRINGLITERAL : '"' (~["\r\n] | '""')* '"';
246248
OCTLITERAL : '&O' [0-8]+ INTEGERTYPESUFFIX?;
247249
HEXLITERAL : '&H' [0-9A-F]+ INTEGERTYPESUFFIX?;
@@ -298,8 +300,10 @@ SINGLEQUOTE : '\'';
298300
UNDERSCORE : '_';
299301
WS : [ \t];
300302
GUIDLITERAL : '{' [0-9A-F]+ '-' [0-9A-F]+ '-' [0-9A-F]+ '-' [0-9A-F]+ '-' [0-9A-F]+ '}';
301-
IDENTIFIER : ~[[\]()\r\n\t.,'"|!@#$%^&*\-+:=; 0-9-/\\-] ~[[\]()\r\n\t.,'"|!@#$%^&*\-+:=; -]*;
303+
IDENTIFIER : ~[[\](){}\r\n\t.,'"|!@#$%^&*\-+:=; 0-9-/\\-] ~[[\](){}\r\n\t.,'"|!@#$%^&*\-+:=; -]*;
302304
LINE_CONTINUATION : [ \t]* UNDERSCORE [ \t]* '\r'? '\n';
305+
// The following rule is needed in order to capture hex literals without format prefixes which start with a digit. Needed for VBForm resources.
306+
BARE_HEX_LITERAL : [0-9] [0-9a-fA-F]*;
303307
fragment LETTER : [a-zA-Z_äöüÄÖÜ];
304308
fragment DIGIT : [0-9];
305309
fragment LETTERORDIGIT : [a-zA-Z0-9_äöüÄÖÜ];

Rubberduck.Parsing/Grammar/VBAParser.g4

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,16 @@ moduleConfigProperty :
6262
;
6363

6464
moduleConfigElement :
65-
unrestrictedIdentifier whiteSpace? EQ whiteSpace? expression (COLON numberLiteral)? endOfStatement
65+
(unrestrictedIdentifier | lExpression) whiteSpace? EQ whiteSpace? (shortcut | resource | expression) endOfStatement
66+
;
67+
68+
shortcut :
69+
(POW singleLetter)
70+
| ((PERCENT | PLUS? POW?) L_BRACE IDENTIFIER R_BRACE)
71+
;
72+
73+
resource :
74+
DOLLAR? expression COLON (numberLiteral | BARE_HEX_LITERAL | unrestrictedIdentifier)
6675
;
6776

6877
moduleAttributes : (attributeStmt endOfStatement)*;
@@ -552,7 +561,7 @@ withStmt :
552561
;
553562

554563
// Special forms with special syntax, only available in VBA reports or VB6 forms and pictureboxes.
555-
lineSpecialForm : expression whiteSpace (STEP whiteSpace?)? tuple MINUS (STEP whiteSpace?)? tuple whiteSpace? (COMMA whiteSpace? expression)? whiteSpace? (COMMA whiteSpace? lineSpecialFormOption)?;
564+
lineSpecialForm : expression whiteSpace ((STEP whiteSpace?)? tuple)? MINUS (STEP whiteSpace?)? tuple whiteSpace? (COMMA whiteSpace? expression)? whiteSpace? (COMMA whiteSpace? lineSpecialFormOption)?;
556565
circleSpecialForm : (expression whiteSpace? DOT whiteSpace?)? CIRCLE whiteSpace (STEP whiteSpace?)? tuple (whiteSpace? COMMA whiteSpace? expression)+;
557566
scaleSpecialForm : (expression whiteSpace? DOT whiteSpace?)? SCALE whiteSpace tuple whiteSpace? MINUS whiteSpace? tuple;
558567
pSetSpecialForm : (expression whiteSpace? DOT whiteSpace?)? PSET (whiteSpace STEP)? whiteSpace? tuple whiteSpace? (COMMA whiteSpace? expression)?;

Rubberduck.Resources/Settings/AutoCompletesPage.Designer.cs

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)