Skip to content

Commit 74f9525

Browse files
committed
Merge pull request #853 from retailcoder/next
Async/keyhook-triggered parser
2 parents da56440 + 61eedc9 commit 74f9525

File tree

150 files changed

+14726
-14723
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+14726
-14723
lines changed

RetailCoder.VBE/App.cs

Lines changed: 108 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,114 @@
11
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
24
using System.Globalization;
5+
using System.Linq;
6+
using System.Runtime.InteropServices;
7+
using System.Threading;
8+
using System.Threading.Tasks;
39
using System.Windows.Forms;
10+
using Microsoft.Vbe.Interop;
411
using NLog;
12+
using Rubberduck.Common;
513
using Rubberduck.Inspections;
614
using Rubberduck.Parsing;
7-
using Rubberduck.Parsing.VBA;
815
using Rubberduck.Settings;
916
using Rubberduck.UI;
1017
using Rubberduck.UI.Command.MenuItems;
1118
using Rubberduck.UI.ParserErrors;
19+
using Rubberduck.VBEditor.Extensions;
1220

1321
namespace Rubberduck
1422
{
1523
public class App : IDisposable
1624
{
25+
private readonly VBE _vbe;
1726
private readonly IMessageBox _messageBox;
1827
private readonly IParserErrorsPresenterFactory _parserErrorsPresenterFactory;
19-
private readonly IRubberduckParserFactory _parserFactory;
28+
private readonly IRubberduckParser _parser;
2029
private readonly IInspectorFactory _inspectorFactory;
2130
private readonly IGeneralConfigService _configService;
2231
private readonly IAppMenu _appMenus;
32+
private readonly ParserStateCommandBar _stateBar;
33+
private readonly IKeyHook _hook;
2334

24-
private IParserErrorsPresenter _parserErrorsPresenter;
2535
private readonly Logger _logger;
26-
private IRubberduckParser _parser;
2736

2837
private Configuration _config;
2938

30-
public App(IMessageBox messageBox,
39+
private readonly ConcurrentDictionary<VBComponent, CancellationTokenSource> _tokenSources =
40+
new ConcurrentDictionary<VBComponent, CancellationTokenSource>();
41+
42+
public App(VBE vbe, IMessageBox messageBox,
3143
IParserErrorsPresenterFactory parserErrorsPresenterFactory,
32-
IRubberduckParserFactory parserFactory,
44+
IRubberduckParser parser,
3345
IInspectorFactory inspectorFactory,
3446
IGeneralConfigService configService,
35-
IAppMenu appMenus)
47+
IAppMenu appMenus,
48+
ParserStateCommandBar stateBar,
49+
IKeyHook hook)
3650
{
51+
_vbe = vbe;
3752
_messageBox = messageBox;
3853
_parserErrorsPresenterFactory = parserErrorsPresenterFactory;
39-
_parserFactory = parserFactory;
54+
_parser = parser;
4055
_inspectorFactory = inspectorFactory;
4156
_configService = configService;
4257
_appMenus = appMenus;
58+
_stateBar = stateBar;
59+
_hook = hook;
4360
_logger = LogManager.GetCurrentClassLogger();
4461

62+
_hook.KeyPressed += _hook_KeyPressed;
4563
_configService.SettingsChanged += _configService_SettingsChanged;
64+
_parser.State.StateChanged += Parser_StateChanged;
65+
_stateBar.Refresh += _stateBar_Refresh;
66+
}
67+
68+
private void _stateBar_Refresh(object sender, EventArgs e)
69+
{
70+
Task.Run(() => ParseAll());
71+
}
72+
73+
private void Parser_StateChanged(object sender, EventArgs e)
74+
{
75+
_appMenus.EvaluateCanExecute(_parser.State);
76+
}
77+
78+
private async void _hook_KeyPressed(object sender, KeyHookEventArgs e)
79+
{
80+
await ParseComponentAsync(e.Component);
81+
}
82+
83+
private async Task ParseComponentAsync(VBComponent component, bool resolve = true)
84+
{
85+
var tokenSource = RenewTokenSource(component);
86+
87+
var token = tokenSource.Token;
88+
await _parser.ParseAsync(component, token);
89+
90+
if (resolve && !token.IsCancellationRequested)
91+
{
92+
using (var source = new CancellationTokenSource())
93+
{
94+
_parser.Resolve(source.Token);
95+
}
96+
}
97+
}
98+
99+
private CancellationTokenSource RenewTokenSource(VBComponent component)
100+
{
101+
if (_tokenSources.ContainsKey(component))
102+
{
103+
CancellationTokenSource existingTokenSource;
104+
_tokenSources.TryRemove(component, out existingTokenSource);
105+
existingTokenSource.Cancel();
106+
existingTokenSource.Dispose();
107+
}
108+
109+
var tokenSource = new CancellationTokenSource();
110+
_tokenSources[component] = tokenSource;
111+
return tokenSource;
46112
}
47113

48114
public void Startup()
@@ -51,12 +117,35 @@ public void Startup()
51117

52118
_appMenus.Initialize();
53119
_appMenus.Localize();
120+
121+
Task.Delay(1000).ContinueWith(t =>
122+
{
123+
_parser.State.AddBuiltInDeclarations(_vbe.HostApplication());
124+
ParseAll();
125+
});
126+
127+
_hook.Attach();
128+
}
129+
130+
private void ParseAll()
131+
{
132+
var components = _vbe.VBProjects.Cast<VBProject>()
133+
.SelectMany(project => project.VBComponents.Cast<VBComponent>());
134+
135+
var result = Parallel.ForEach(components, async component => { await ParseComponentAsync(component, false); });
136+
137+
if (result.IsCompleted)
138+
{
139+
using (var tokenSource = new CancellationTokenSource())
140+
{
141+
_parser.Resolve(tokenSource.Token);
142+
}
143+
}
54144
}
55145

56146
private void CleanReloadConfig()
57147
{
58148
LoadConfig();
59-
CleanUp();
60149
Setup();
61150
}
62151

@@ -87,44 +176,23 @@ private void LoadConfig()
87176

88177
private void Setup()
89178
{
90-
_parser = _parserFactory.Create();
91-
_parser.ParseStarted += _parser_ParseStarted;
92-
_parser.ParserError += _parser_ParserError;
93-
94179
_inspectorFactory.Create();
95-
96-
_parserErrorsPresenter = _parserErrorsPresenterFactory.Create();
97-
}
98-
99-
private void _parser_ParseStarted(object sender, ParseStartedEventArgs e)
100-
{
101-
_parserErrorsPresenter.Clear();
102-
}
103-
104-
private void _parser_ParserError(object sender, ParseErrorEventArgs e)
105-
{
106-
_parserErrorsPresenter.AddError(e);
107-
_parserErrorsPresenter.Show();
180+
_parserErrorsPresenterFactory.Create();
108181
}
109182

110183
public void Dispose()
111184
{
112-
Dispose(true);
113-
}
185+
_hook.KeyPressed -= _hook_KeyPressed;
186+
_configService.SettingsChanged -= _configService_SettingsChanged;
187+
_parser.State.StateChanged -= Parser_StateChanged;
114188

115-
protected virtual void Dispose(bool disposing)
116-
{
117-
if (!disposing) { return; }
118-
119-
CleanUp();
120-
}
121-
122-
private void CleanUp()
123-
{
124-
if (_parser != null)
189+
if (_tokenSources.Any())
125190
{
126-
_parser.ParseStarted -= _parser_ParseStarted;
127-
_parser.ParserError -= _parser_ParserError;
191+
foreach (var tokenSource in _tokenSources)
192+
{
193+
tokenSource.Value.Cancel();
194+
tokenSource.Value.Dispose();
195+
}
128196
}
129197
}
130198
}

RetailCoder.VBE/AppMenu.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using Rubberduck.Parsing.VBA;
23
using Rubberduck.UI.Command.MenuItems;
34
using Rubberduck.UI.Command.MenuItems.ParentMenus;
45

@@ -21,11 +22,11 @@ public void Initialize()
2122
}
2223
}
2324

24-
public void SetCommandButtonEnabledState(string key, bool isEnabled = true)
25+
public void EvaluateCanExecute(RubberduckParserState state)
2526
{
2627
foreach (var menu in _menus)
2728
{
28-
menu.SetCommandButtonEnabledState(key, isEnabled);
29+
menu.EvaluateCanExecute(state);
2930
}
3031
}
3132

0 commit comments

Comments
 (0)