Skip to content

Commit 1c2a2a7

Browse files
authored
Merge pull request #2698 from comintern/next
Fix thread safety in SubClassWindow, Indenter fix, focus switching fixes.
2 parents 4f5c05e + 8632df5 commit 1c2a2a7

File tree

12 files changed

+125
-88
lines changed

12 files changed

+125
-88
lines changed

RetailCoder.VBE/App.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,15 @@ private void _vbe_FocusChanged(object sender, WindowChangedEventArgs e)
9494
{
9595
if (e.EventType == WindowChangedEventArgs.FocusType.GotFocus)
9696
{
97-
RefreshSelection(e.Window);
97+
switch (e.Window.Type)
98+
{
99+
case WindowKind.Designer:
100+
RefreshSelection(e.Window);
101+
break;
102+
case WindowKind.CodeWindow:
103+
RefreshSelection(e.CodePane);
104+
break;
105+
}
98106
}
99107
}
100108

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ internal void RefreshFinder(IHostApplication host)
7272
DeclarationFinder = new DeclarationFinder(AllDeclarations, AllAnnotations, host);
7373
}
7474

75-
private IVBE _vbe;
75+
private readonly IVBE _vbe;
7676
public RubberduckParserState(IVBE vbe)
7777
{
7878
var values = Enum.GetValues(typeof(ParserState));
@@ -82,32 +82,27 @@ public RubberduckParserState(IVBE vbe)
8282
}
8383

8484
_vbe = vbe;
85-
86-
if (_vbe != null && _vbe.VBProjects != null)
87-
{
88-
VBProjects.ProjectAdded += Sinks_ProjectAdded;
89-
VBProjects.ProjectRemoved += Sinks_ProjectRemoved;
90-
VBProjects.ProjectRenamed += Sinks_ProjectRenamed;
91-
foreach (var project in _vbe.VBProjects.Where(proj => proj.VBComponents != null))
92-
{
93-
AddComponentEventHandlers(project);
94-
}
95-
}
96-
85+
AddEventHandlers();
9786
IsEnabled = true;
9887
}
9988

10089
#region Event Handling
10190

102-
private void AddComponentEventHandlers(IVBProject project)
91+
private void AddEventHandlers()
10392
{
93+
VBProjects.ProjectAdded += Sinks_ProjectAdded;
94+
VBProjects.ProjectRemoved += Sinks_ProjectRemoved;
95+
VBProjects.ProjectRenamed += Sinks_ProjectRenamed;
10496
VBComponents.ComponentAdded += Sinks_ComponentAdded;
10597
VBComponents.ComponentRemoved += Sinks_ComponentRemoved;
10698
VBComponents.ComponentRenamed += Sinks_ComponentRenamed;
10799
}
108100

109-
private void RemoveComponentEventHandlers(IVBProject project)
101+
private void RemoveEventHandlers()
110102
{
103+
VBProjects.ProjectAdded += Sinks_ProjectAdded;
104+
VBProjects.ProjectRemoved += Sinks_ProjectRemoved;
105+
VBProjects.ProjectRenamed += Sinks_ProjectRenamed;
111106
VBComponents.ComponentAdded -= Sinks_ComponentAdded;
112107
VBComponents.ComponentRemoved -= Sinks_ComponentRemoved;
113108
VBComponents.ComponentRenamed -= Sinks_ComponentRenamed;
@@ -118,8 +113,6 @@ private void Sinks_ProjectAdded(object sender, ProjectEventArgs e)
118113
if (!e.Project.VBE.IsInDesignMode) { return; }
119114

120115
Logger.Debug("Project '{0}' was added.", e.ProjectId);
121-
AddComponentEventHandlers(e.Project);
122-
123116
RefreshProjects(_vbe); // note side-effect: assigns ProjectId/HelpFile
124117
OnParseRequested(sender);
125118
}
@@ -129,8 +122,6 @@ private void Sinks_ProjectRemoved(object sender, ProjectEventArgs e)
129122
if (!e.Project.VBE.IsInDesignMode) { return; }
130123

131124
Debug.Assert(e.ProjectId != null);
132-
RemoveComponentEventHandlers(e.Project);
133-
134125
RemoveProject(e.ProjectId, true);
135126
OnParseRequested(sender);
136127
}
@@ -1110,16 +1101,7 @@ public void Dispose()
11101101
CoClasses.Clear();
11111102
}
11121103

1113-
if (_vbe != null && _vbe.VBProjects != null)
1114-
{
1115-
VBProjects.ProjectAdded -= Sinks_ProjectAdded;
1116-
VBProjects.ProjectRemoved -= Sinks_ProjectRemoved;
1117-
VBProjects.ProjectRenamed -= Sinks_ProjectRenamed;
1118-
foreach (var project in _vbe.VBProjects.Where(proj => proj.VBComponents != null))
1119-
{
1120-
RemoveComponentEventHandlers(project);
1121-
}
1122-
}
1104+
RemoveEventHandlers();
11231105

11241106
_moduleStates.Clear();
11251107
_declarationSelections.Clear();

Rubberduck.SmartIndenter/AbsoluteCodeLine.cs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ namespace Rubberduck.SmartIndenter
1010
internal class AbsoluteCodeLine
1111
{
1212
private const string StupidLineEnding = ": _";
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));
1513
private static readonly Regex LineNumberRegex = new Regex(@"^(?<number>(-?\d+)|(&H[0-9A-F]{1,8}))\s+(?<code>.*)", RegexOptions.ExplicitCapture);
1614
private static readonly Regex EndOfLineCommentRegex = new Regex(@"^(?!(Rem\s)|('))(?<code>[^']*)(\s(?<comment>'.*))$", RegexOptions.ExplicitCapture);
1715
private static readonly Regex ProcedureStartRegex = new Regex(@"^(Public\s|Private\s|Friend\s)?(Static\s)?(Sub|Function|Property\s(Let|Get|Set))\s");
@@ -33,8 +31,6 @@ internal class AbsoluteCodeLine
3331
private readonly bool _stupidLineEnding;
3432
private readonly string[] _segments;
3533
private readonly StringLiteralAndBracketEscaper _escaper;
36-
//private List<string> _strings;
37-
//private List<string> _brackets;
3834

3935
public AbsoluteCodeLine(string code, IIndenterSettings settings) : this(code, settings, null) { }
4036

@@ -61,8 +57,6 @@ public AbsoluteCodeLine(string code, IIndenterSettings settings, AbsoluteCodeLin
6157
ExtractLineNumber();
6258
ExtractEndOfLineComment();
6359

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();
6660
_segments = _code.Split(new[] { ": " }, StringSplitOptions.None);
6761
}
6862

@@ -267,38 +261,29 @@ public string Indent(int indents, bool atProcStart, bool absolute = false)
267261
}
268262

269263
var code = string.Join(": ", _segments);
270-
if (_escaper.EscapedStrings.Any())
271-
{
272-
code = _escaper.EscapedStrings.Aggregate(code, (current, literal) => StringReplaceRegex.Replace(current, literal, 1));
273-
}
274-
if (_escaper.EscapedBrackets.Any())
275-
{
276-
code = _escaper.EscapedBrackets.Aggregate(code, (current, expr) => BracketReplaceRegex.Replace(current, expr, 1));
277-
}
278-
279264
code = string.Join(string.Empty, number, new string(' ', gap), code);
280265
if (string.IsNullOrEmpty(EndOfLineComment))
281266
{
282-
return code + (_stupidLineEnding ? StupidLineEnding : string.Empty);
267+
return _escaper.UnescapeIndented(code + (_stupidLineEnding ? StupidLineEnding : string.Empty));
283268
}
284269

285270
var position = Original.LastIndexOf(EndOfLineComment, StringComparison.Ordinal);
286271
switch (_settings.EndOfLineCommentStyle)
287272
{
288273
case EndOfLineCommentStyle.Absolute:
289-
return string.Format("{0}{1}{2}{3}", code, new string(' ', Math.Max(position - code.Length, 1)),
290-
EndOfLineComment, _stupidLineEnding ? StupidLineEnding : string.Empty);
274+
return _escaper.UnescapeIndented(string.Format("{0}{1}{2}{3}", code, new string(' ', Math.Max(position - code.Length, 1)),
275+
EndOfLineComment, _stupidLineEnding ? StupidLineEnding : string.Empty));
291276
case EndOfLineCommentStyle.SameGap:
292277
var uncommented = Original.Substring(0, position - 1);
293-
return string.Format("{0}{1}{2}{3}", code, new string(' ', uncommented.Length - uncommented.TrimEnd().Length + 1),
294-
EndOfLineComment, _stupidLineEnding ? StupidLineEnding : string.Empty);
278+
return _escaper.UnescapeIndented(string.Format("{0}{1}{2}{3}", code, new string(' ', uncommented.Length - uncommented.TrimEnd().Length + 1),
279+
EndOfLineComment, _stupidLineEnding ? StupidLineEnding : string.Empty));
295280
case EndOfLineCommentStyle.StandardGap:
296-
return string.Format("{0}{1}{2}{3}", code, new string(' ', _settings.IndentSpaces * 2), EndOfLineComment,
297-
_stupidLineEnding ? StupidLineEnding : string.Empty);
281+
return _escaper.UnescapeIndented(string.Format("{0}{1}{2}{3}", code, new string(' ', _settings.IndentSpaces * 2), EndOfLineComment,
282+
_stupidLineEnding ? StupidLineEnding : string.Empty));
298283
case EndOfLineCommentStyle.AlignInColumn:
299284
var align = _settings.EndOfLineCommentColumnSpaceAlignment - code.Length;
300-
return string.Format("{0}{1}{2}{3}", code, new string(' ', Math.Max(align - 1, 1)), EndOfLineComment,
301-
_stupidLineEnding ? StupidLineEnding : string.Empty);
285+
return _escaper.UnescapeIndented(string.Format("{0}{1}{2}{3}", code, new string(' ', Math.Max(align - 1, 1)), EndOfLineComment,
286+
_stupidLineEnding ? StupidLineEnding : string.Empty));
302287
default:
303288
throw new InvalidEnumArgumentException();
304289
}

Rubberduck.SmartIndenter/Rubberduck.SmartIndenter.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
<Compile Include="IndenterSettings.cs" />
5757
<Compile Include="LogicalCodeLine.cs" />
5858
<Compile Include="Properties\AssemblyInfo.cs" />
59-
<Compile Include="Selection.cs" />
6059
<Compile Include="StringLiteralAndBracketEscaper.cs" />
6160
</ItemGroup>
6261
<ItemGroup>

Rubberduck.SmartIndenter/Selection.cs

Lines changed: 0 additions & 3 deletions
This file was deleted.

Rubberduck.SmartIndenter/StringLiteralAndBracketEscaper.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using System.Text.RegularExpressions;
34

45
namespace Rubberduck.SmartIndenter
56
{
67
internal class StringLiteralAndBracketEscaper
78
{
89
public const char StringPlaceholder = '\a';
9-
public const char BracketPlaceholder = '\x2';
10+
public const char BracketPlaceholder = '\x02';
11+
12+
private static readonly Regex StringReplaceRegex = new Regex("\a+");
13+
private static readonly Regex BracketReplaceRegex = new Regex("\x02+");
1014

1115
private readonly List<string> _strings = new List<string>();
1216
private readonly List<string> _brackets = new List<string>();
@@ -18,6 +22,20 @@ internal class StringLiteralAndBracketEscaper
1822
public IEnumerable<string> EscapedStrings { get { return _strings; } }
1923
public IEnumerable<string> EscapedBrackets { get { return _brackets; } }
2024

25+
public string UnescapeIndented(string indented)
26+
{
27+
var code = indented;
28+
if (_strings.Any())
29+
{
30+
code = _strings.Aggregate(code, (current, literal) => StringReplaceRegex.Replace(current, literal, 1));
31+
}
32+
if (_brackets.Any())
33+
{
34+
code = _brackets.Aggregate(code, (current, expr) => BracketReplaceRegex.Replace(current, expr, 1));
35+
}
36+
return code;
37+
}
38+
2139
public StringLiteralAndBracketEscaper(string code)
2240
{
2341
_unescaped = code;
@@ -63,8 +81,8 @@ public StringLiteralAndBracketEscaper(string code)
6381
continue;
6482
}
6583
bracketed = false;
66-
_brackets.Add(new string(chars.Skip(brkpos).Take(c - brkpos).ToArray()));
67-
for (var e = brkpos; e < c; e++)
84+
_brackets.Add(new string(chars.Skip(brkpos).Take(c - brkpos + 1).ToArray()));
85+
for (var e = brkpos; e <= c; e++)
6886
{
6987
chars[e] = BracketPlaceholder;
7088
}

Rubberduck.VBEEditor/Events/VBEEvents.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ private static void AttachWindow(IntPtr hwnd)
9292
Debug.Assert(!TrackedWindows.ContainsKey(hwnd));
9393
var window = GetWindowFromHwnd(hwnd);
9494
if (window == null) return;
95-
var source = window.Type == WindowKind.CodeWindow ? new CodePaneSubclass(hwnd) as IWindowEventProvider: new DesignerWindowSubclass(hwnd);
95+
var source = window.Type == WindowKind.CodeWindow
96+
? new CodePaneSubclass(hwnd, GetCodePaneFromHwnd(hwnd)) as IWindowEventProvider
97+
: new DesignerWindowSubclass(hwnd);
9698
var info = new WindowInfo(hwnd, window, source);
9799
source.FocusChange += FocusDispatcher;
98100
TrackedWindows.Add(hwnd, info);

Rubberduck.VBEEditor/Events/WindowChangedEventArgs.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ public enum FocusType
1313

1414
public IntPtr Hwnd { get; private set; }
1515
public IWindow Window { get; private set; }
16+
public ICodePane CodePane { get; private set; }
1617
public FocusType EventType { get; private set; }
1718

18-
public WindowChangedEventArgs(IntPtr hwnd, IWindow window, FocusType type)
19+
public WindowChangedEventArgs(IntPtr hwnd, IWindow window, ICodePane pane, FocusType type)
1920
{
2021
Hwnd = hwnd;
2122
Window = window;
23+
CodePane = pane;
2224
EventType = type;
2325
}
2426
}
Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
using System;
2+
using Rubberduck.VBEditor.Events;
3+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
24

35
namespace Rubberduck.VBEditor.WindowsApi
46
{
7+
//Stub for code pane replacement. :-)
58
internal class CodePaneSubclass : FocusSource
69
{
7-
//Stub for code pane replacement. :-)
8-
internal CodePaneSubclass(IntPtr hwnd) : base(hwnd) { }
10+
private readonly ICodePane _pane;
11+
12+
public ICodePane CodePane { get { return _pane; } }
13+
14+
internal CodePaneSubclass(IntPtr hwnd, ICodePane pane) : base(hwnd)
15+
{
16+
_pane = pane;
17+
}
18+
19+
protected override void DispatchFocusEvent(WindowChangedEventArgs.FocusType type)
20+
{
21+
var window = VBEEvents.GetWindowInfoFromHwnd(Hwnd);
22+
if (window == null)
23+
{
24+
return;
25+
}
26+
OnFocusChange(new WindowChangedEventArgs(window.Value.Hwnd, window.Value.Window, _pane, type));
27+
}
928
}
1029
}

Rubberduck.VBEEditor/WindowsApi/FocusSource.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,34 @@ internal abstract class FocusSource : SubclassingWindow, IWindowEventProvider
99
protected FocusSource(IntPtr hwnd) : base(hwnd, hwnd) { }
1010

1111
public event EventHandler<WindowChangedEventArgs> FocusChange;
12-
private void OnFocusChange(WindowChangedEventArgs.FocusType type)
12+
protected void OnFocusChange(WindowChangedEventArgs eventArgs)
1313
{
1414
if (FocusChange != null)
1515
{
16-
var window = VBEEvents.GetWindowInfoFromHwnd(Hwnd);
17-
if (window == null)
18-
{
19-
return;
20-
}
21-
FocusChange.Invoke(this, new WindowChangedEventArgs(window.Value.Hwnd, window.Value.Window, type));
16+
FocusChange.Invoke(this, eventArgs);
2217
}
23-
}
18+
}
19+
20+
protected virtual void DispatchFocusEvent(WindowChangedEventArgs.FocusType type)
21+
{
22+
var window = VBEEvents.GetWindowInfoFromHwnd(Hwnd);
23+
if (window == null)
24+
{
25+
return;
26+
}
27+
OnFocusChange(new WindowChangedEventArgs(Hwnd, window.Value.Window, null, type));
28+
}
2429

2530
public override int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr lParam, IntPtr uIdSubclass, IntPtr dwRefData)
2631
{
2732
switch ((uint)msg)
2833
{
2934
case (uint)WM.SETFOCUS:
30-
OnFocusChange(WindowChangedEventArgs.FocusType.GotFocus);
35+
36+
DispatchFocusEvent(WindowChangedEventArgs.FocusType.GotFocus);
3137
break;
3238
case (uint)WM.KILLFOCUS:
33-
OnFocusChange(WindowChangedEventArgs.FocusType.LostFocus);
39+
DispatchFocusEvent(WindowChangedEventArgs.FocusType.LostFocus);
3440
break;
3541
}
3642
return base.SubClassProc(hWnd, msg, wParam, lParam, uIdSubclass, dwRefData);

0 commit comments

Comments
 (0)