Skip to content

Commit b0687e1

Browse files
authored
Merge pull request #2608 from comintern/next
Fix clipboard text for inspections, Fix string literals in Indenter function aligner - Closes #2604
2 parents e51187b + 9e0fb3c commit b0687e1

File tree

16 files changed

+238
-130
lines changed

16 files changed

+238
-130
lines changed

RetailCoder.VBE/Inspections/Abstract/IInspectionResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ public interface IInspectionResult : IComparable<IInspectionResult>, IComparable
1111
QualifiedSelection QualifiedSelection { get; }
1212
IInspection Inspection { get; }
1313
object[] ToArray();
14+
string ToClipboardString();
1415
}
1516
}

RetailCoder.VBE/Inspections/Abstract/InspectionResultBase.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.IO;
23
using System.Linq;
34
using Antlr4.Runtime;
45
using Rubberduck.Inspections.Resources;
@@ -87,18 +88,33 @@ public virtual int CompareTo(IInspectionResult other)
8788
return Inspection.CompareTo(other.Inspection);
8889
}
8990

90-
//public override string ToString()
91-
//{
92-
// var module = QualifiedSelection.QualifiedName;
93-
// return string.Format(
94-
// InspectionsUI.QualifiedSelectionInspection,
95-
// Inspection.Severity,
96-
// Description,
97-
// "(" + module.ProjectDisplayName + ")",
98-
// module.ProjectName,
99-
// module.ComponentName,
100-
// QualifiedSelection.Selection.StartLine);
101-
//}
91+
/// <summary>
92+
/// WARNING: This property can have side effects. It can change the ActiveVBProject if the result has a null Declaration,
93+
/// which causes a flicker in the VBE. This should only be called if it is *absolutely* necessary.
94+
/// </summary>
95+
public string ToClipboardString()
96+
{
97+
var module = QualifiedSelection.QualifiedName;
98+
var documentName = _target != null ? _target.ProjectDisplayName : string.Empty;
99+
if (string.IsNullOrEmpty(documentName))
100+
{
101+
var component = module.Component;
102+
documentName = component != null ? component.ParentProject.ProjectDisplayName : string.Empty;
103+
}
104+
if (string.IsNullOrEmpty(documentName))
105+
{
106+
documentName = Path.GetFileName(module.ProjectPath);
107+
}
108+
109+
return string.Format(
110+
InspectionsUI.QualifiedSelectionInspection,
111+
Inspection.Severity,
112+
Description,
113+
"(" + documentName + ")",
114+
module.ProjectName,
115+
module.ComponentName,
116+
QualifiedSelection.Selection.StartLine);
117+
}
102118

103119
public virtual NavigateCodeEventArgs GetNavigationArgs()
104120
{

RetailCoder.VBE/UI/Inspections/InspectionResultsViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ private void ExecuteCopyResultsCommand(object parameter)
430430

431431
var title = string.Format(resource, DateTime.Now.ToString(CultureInfo.InvariantCulture), _results.Count);
432432

433-
var textResults = title + Environment.NewLine + string.Join("", _results.Select(result => result.ToString() + Environment.NewLine).ToArray());
433+
var textResults = title + Environment.NewLine + string.Join("", _results.Select(result => result.ToClipboardString() + Environment.NewLine).ToArray());
434434
var csvResults = ExportFormatter.Csv(aResults, title,ColumnInfos);
435435
var htmlResults = ExportFormatter.HtmlClipboardFragment(aResults, title,ColumnInfos);
436436
var rtfResults = ExportFormatter.RTF(aResults, title);

Rubberduck.Parsing/Symbols/ProjectDeclaration.cs

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Text.RegularExpressions;
2-
using Rubberduck.Parsing.ComReflection;
1+
using Rubberduck.Parsing.ComReflection;
32
using Rubberduck.VBEditor;
43
using System.Collections.Generic;
54
using System.Linq;
@@ -72,9 +71,6 @@ public void AddProjectReference(string referencedProjectId, int priority)
7271
_projectReferences.Add(new ProjectReference(referencedProjectId, priority));
7372
}
7473

75-
private static readonly Regex CaptionProjectRegex = new Regex(@"^(?:[^-]+)(?:\s-\s)(?<project>.+)(?:\s-\s.*)?$");
76-
private static readonly Regex OpenModuleRegex = new Regex(@"^(?<project>.+)(?<module>\s-\s\[.*\((Code|UserForm)\)\])$");
77-
7874
private string _displayName;
7975
/// <summary>
8076
/// WARNING: This property has side effects. It changes the ActiveVBProject, which causes a flicker in the VBE.
@@ -88,39 +84,8 @@ public override string ProjectDisplayName
8884
{
8985
return _displayName;
9086
}
91-
92-
if (_project == null)
93-
{
94-
_displayName = string.Empty;
95-
return _displayName;
96-
}
97-
98-
var vbe = _project.VBE;
99-
var activeProject = vbe.ActiveVBProject;
100-
var mainWindow = vbe.MainWindow;
101-
{
102-
try
103-
{
104-
if (_project.HelpFile != activeProject.HelpFile)
105-
{
106-
vbe.ActiveVBProject = _project;
107-
}
108-
109-
var caption = mainWindow.Caption;
110-
if (CaptionProjectRegex.IsMatch(caption))
111-
{
112-
caption = CaptionProjectRegex.Matches(caption)[0].Groups["project"].Value;
113-
_displayName = OpenModuleRegex.IsMatch(caption)
114-
? OpenModuleRegex.Matches(caption)[0].Groups["project"].Value
115-
: caption;
116-
}
117-
}
118-
catch
119-
{
120-
_displayName = string.Empty;
121-
}
122-
return _displayName;
123-
}
87+
_displayName = _project != null ? _project.ProjectDisplayName : string.Empty;
88+
return _displayName;
12489
}
12590
}
12691
}

Rubberduck.SmartIndenter/AbsoluteCodeLine.cs

Lines changed: 21 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ namespace Rubberduck.SmartIndenter
1010
internal class AbsoluteCodeLine
1111
{
1212
private const string StupidLineEnding = ": _";
13-
private const char StringPlaceholder = '\a';
14-
private const char BracketPlaceholder = '\x2';
15-
private static readonly Regex StringReplaceRegex = new Regex(StringPlaceholder.ToString(CultureInfo.InvariantCulture));
16-
private static readonly Regex BracketReplaceRegex = new Regex(BracketPlaceholder.ToString(CultureInfo.InvariantCulture));
13+
private static readonly Regex StringReplaceRegex = new Regex(StringLiteralAndBracketEscaper.StringPlaceholder.ToString(CultureInfo.InvariantCulture));
14+
private static readonly Regex BracketReplaceRegex = new Regex(StringLiteralAndBracketEscaper.BracketPlaceholder.ToString(CultureInfo.InvariantCulture));
1715
private static readonly Regex LineNumberRegex = new Regex(@"^(?<number>(-?\d+)|(&H[0-9A-F]{1,8}))\s+(?<code>.*)", RegexOptions.ExplicitCapture);
1816
private static readonly Regex EndOfLineCommentRegex = new Regex(@"^(?!(Rem\s)|('))(?<code>[^']*)(\s(?<comment>'.*))$", RegexOptions.ExplicitCapture);
1917
private static readonly Regex ProcedureStartRegex = new Regex(@"^(Public\s|Private\s|Friend\s)?(Static\s)?(Sub|Function|Property\s(Let|Get|Set))\s");
@@ -34,8 +32,9 @@ internal class AbsoluteCodeLine
3432
private string _code;
3533
private readonly bool _stupidLineEnding;
3634
private readonly string[] _segments;
37-
private List<string> _strings;
38-
private List<string> _brackets;
35+
private readonly StringLiteralAndBracketEscaper _escaper;
36+
//private List<string> _strings;
37+
//private List<string> _brackets;
3938

4039
public AbsoluteCodeLine(string code, IIndenterSettings settings) : this(code, settings, null) { }
4140

@@ -56,72 +55,17 @@ public AbsoluteCodeLine(string code, IIndenterSettings settings, AbsoluteCodeLin
5655

5756
Original = code;
5857

59-
ExtractStringLiteralsAndBrackets();
58+
_escaper = new StringLiteralAndBracketEscaper(_code);
59+
_code = _escaper.EscapedString;
60+
6061
ExtractLineNumber();
6162
ExtractEndOfLineComment();
6263

63-
_code = Regex.Replace(_code, StringPlaceholder + "+", StringPlaceholder.ToString(CultureInfo.InvariantCulture));
64-
_code = Regex.Replace(_code, BracketPlaceholder + "+", BracketPlaceholder.ToString(CultureInfo.InvariantCulture)).Trim();
64+
_code = Regex.Replace(_code, StringLiteralAndBracketEscaper.StringPlaceholder + "+", StringLiteralAndBracketEscaper.StringPlaceholder.ToString(CultureInfo.InvariantCulture));
65+
_code = Regex.Replace(_code, StringLiteralAndBracketEscaper.BracketPlaceholder + "+", StringLiteralAndBracketEscaper.BracketPlaceholder.ToString(CultureInfo.InvariantCulture)).Trim();
6566
_segments = _code.Split(new[] { ": " }, StringSplitOptions.None);
6667
}
6768

68-
//TODO: This should be a class.
69-
private void ExtractStringLiteralsAndBrackets()
70-
{
71-
_strings = new List<string>();
72-
_brackets = new List<string>();
73-
74-
var chars = _code.ToCharArray();
75-
var quoted = false;
76-
var bracketed = false;
77-
var ins = 0;
78-
var strpos = 0;
79-
var brkpos = 0;
80-
for (var c = 0; c < chars.Length; c++)
81-
{
82-
if (chars[c] == '"' && !bracketed)
83-
{
84-
if (!quoted)
85-
{
86-
strpos = c;
87-
quoted = true;
88-
continue;
89-
}
90-
if (c + 1 < chars.Length && chars[c] == '"')
91-
{
92-
c++;
93-
}
94-
quoted = false;
95-
_strings.Add(new string(chars.Skip(strpos).Take(c - strpos).ToArray()));
96-
for (var e = strpos; e < c; e++)
97-
{
98-
chars[e] = StringPlaceholder;
99-
}
100-
}
101-
else if (!quoted && !bracketed && chars[c] == '[')
102-
{
103-
bracketed = true;
104-
brkpos = c;
105-
ins++;
106-
}
107-
else if (!quoted && bracketed && chars[c] == ']')
108-
{
109-
ins--;
110-
if (ins != 0)
111-
{
112-
continue;
113-
}
114-
bracketed = false;
115-
_brackets.Add(new string(chars.Skip(brkpos).Take(c - brkpos).ToArray()));
116-
for (var e = brkpos; e < c; e++)
117-
{
118-
chars[e] = BracketPlaceholder;
119-
}
120-
}
121-
}
122-
_code = new string(chars);
123-
}
124-
12569
private void ExtractLineNumber()
12670
{
12771
if (Previous == null || !Previous.HasContinuation)
@@ -162,15 +106,18 @@ public string Escaped
162106
{
163107
get
164108
{
109+
// ReSharper disable LoopCanBeConvertedToQuery
165110
var output = Original;
166-
foreach (var item in _strings)
111+
foreach (var item in _escaper.EscapedStrings)
112+
167113
{
168-
output = output.Replace(item, new string(StringPlaceholder, item.Length));
114+
output = output.Replace(item, new string(StringLiteralAndBracketEscaper.StringPlaceholder, item.Length));
169115
}
170-
foreach (var item in _brackets)
116+
foreach (var item in _escaper.EscapedBrackets)
171117
{
172-
output = output.Replace(item, new string(BracketPlaceholder, item.Length));
118+
output = output.Replace(item, new string(StringLiteralAndBracketEscaper.BracketPlaceholder, item.Length));
173119
}
120+
// ReSharper restore LoopCanBeConvertedToQuery
174121
return output;
175122
}
176123
}
@@ -320,13 +267,13 @@ public string Indent(int indents, bool atProcStart, bool absolute = false)
320267
}
321268

322269
var code = string.Join(": ", _segments);
323-
if (_strings.Any())
270+
if (_escaper.EscapedStrings.Any())
324271
{
325-
code = _strings.Aggregate(code, (current, literal) => StringReplaceRegex.Replace(current, literal, 1));
272+
code = _escaper.EscapedStrings.Aggregate(code, (current, literal) => StringReplaceRegex.Replace(current, literal, 1));
326273
}
327-
if (_brackets.Any())
274+
if (_escaper.EscapedBrackets.Any())
328275
{
329-
code = _brackets.Aggregate(code, (current, expr) => BracketReplaceRegex.Replace(current, expr, 1));
276+
code = _escaper.EscapedBrackets.Aggregate(code, (current, expr) => BracketReplaceRegex.Replace(current, expr, 1));
330277
}
331278

332279
code = string.Join(string.Empty, number, new string(' ', gap), code);

Rubberduck.SmartIndenter/LogicalCodeLine.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Rubberduck.SmartIndenter
77
{
88
internal class LogicalCodeLine
99
{
10-
private List<AbsoluteCodeLine> _lines = new List<AbsoluteCodeLine>();
10+
private readonly List<AbsoluteCodeLine> _lines = new List<AbsoluteCodeLine>();
1111
private AbsoluteCodeLine _rebuilt;
1212
private readonly IIndenterSettings _settings;
1313

@@ -186,6 +186,7 @@ public override string ToString()
186186
//The splitNamed parameter is a straight up hack for fixing https://github.com/rubberduck-vba/Rubberduck/issues/2402
187187
private int FunctionAlign(string line, bool splitNamed)
188188
{
189+
line = new StringLiteralAndBracketEscaper(line).EscapedString;
189190
var stackPos = _alignment.Count;
190191

191192
for (var index = StartIgnoreRegex.Match(line).Length + 1; index <= line.Length; index++)
@@ -194,10 +195,8 @@ private int FunctionAlign(string line, bool splitNamed)
194195
switch (character)
195196
{
196197
case "\a":
197-
while (!line.Substring(index++, 1).Equals("\a")) { }
198-
break;
199198
case "\x2":
200-
while (!line.Substring(index++, 1).Equals("\x2")) { }
199+
index++;
201200
break;
202201
case "(":
203202
//Start of another function => remember this position

Rubberduck.SmartIndenter/Rubberduck.SmartIndenter.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
<Compile Include="LogicalCodeLine.cs" />
5858
<Compile Include="Properties\AssemblyInfo.cs" />
5959
<Compile Include="Selection.cs" />
60+
<Compile Include="StringLiteralAndBracketEscaper.cs" />
6061
</ItemGroup>
6162
<ItemGroup>
6263
<None Include="Legacy\CBtnEvents.cls" />
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace Rubberduck.SmartIndenter
5+
{
6+
internal class StringLiteralAndBracketEscaper
7+
{
8+
public const char StringPlaceholder = '\a';
9+
public const char BracketPlaceholder = '\x2';
10+
11+
private readonly List<string> _strings = new List<string>();
12+
private readonly List<string> _brackets = new List<string>();
13+
private readonly string _unescaped;
14+
private readonly string _escaped;
15+
16+
public string EscapedString { get { return _escaped; } }
17+
public string OriginalString { get { return _unescaped; } }
18+
public IEnumerable<string> EscapedStrings { get { return _strings; } }
19+
public IEnumerable<string> EscapedBrackets { get { return _brackets; } }
20+
21+
public StringLiteralAndBracketEscaper(string code)
22+
{
23+
_unescaped = code;
24+
25+
var chars = _unescaped.ToCharArray();
26+
var quoted = false;
27+
var bracketed = false;
28+
var ins = 0;
29+
var strpos = 0;
30+
var brkpos = 0;
31+
for (var c = 0; c < chars.Length; c++)
32+
{
33+
if (chars[c] == '"' && !bracketed)
34+
{
35+
if (!quoted)
36+
{
37+
strpos = c;
38+
quoted = true;
39+
continue;
40+
}
41+
if (c + 1 < chars.Length && chars[c] == '"')
42+
{
43+
c++;
44+
}
45+
quoted = false;
46+
_strings.Add(new string(chars.Skip(strpos).Take(c - strpos).ToArray()));
47+
for (var e = strpos; e < c; e++)
48+
{
49+
chars[e] = StringPlaceholder;
50+
}
51+
}
52+
else if (!quoted && !bracketed && chars[c] == '[')
53+
{
54+
bracketed = true;
55+
brkpos = c;
56+
ins++;
57+
}
58+
else if (!quoted && bracketed && chars[c] == ']')
59+
{
60+
ins--;
61+
if (ins != 0)
62+
{
63+
continue;
64+
}
65+
bracketed = false;
66+
_brackets.Add(new string(chars.Skip(brkpos).Take(c - brkpos).ToArray()));
67+
for (var e = brkpos; e < c; e++)
68+
{
69+
chars[e] = BracketPlaceholder;
70+
}
71+
}
72+
}
73+
_escaped = new string(chars);
74+
}
75+
}
76+
}

Rubberduck.VBEEditor/QualifiedModuleName.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public QualifiedMemberName QualifyMemberName(string member)
101101
public string Name { get { return ToString(); } }
102102

103103
private readonly string _projectName;
104-
public string ProjectName { get { return _projectName; } }
104+
public string ProjectName { get { return _projectName ?? string.Empty; } }
105105

106106
private readonly string _projectPath;
107107
public string ProjectPath { get { return _projectPath; } }

0 commit comments

Comments
 (0)