Skip to content

Commit 9888833

Browse files
committed
Added StaTaskScheduler. TODO: use it to schedule everything that comes anywhere near COM interop. Yup. That's everything.
1 parent f55ce1b commit 9888833

File tree

5 files changed

+146
-44
lines changed

5 files changed

+146
-44
lines changed

RetailCoder.VBE/App.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Rubberduck.UI.Command.MenuItems;
1818
using Infralution.Localization.Wpf;
1919
using Rubberduck.Common.Dispatch;
20+
using Rubberduck.Common.Hotkeys;
2021

2122
namespace Rubberduck
2223
{
@@ -42,6 +43,8 @@ public class App : IDisposable
4243
private readonly IDictionary<VBComponents, Tuple<IConnectionPoint, int>> _componentsEventsConnectionPoints =
4344
new Dictionary<VBComponents, Tuple<IConnectionPoint, int>>();
4445

46+
private readonly IDictionary<Type, Action> _hookActions;
47+
4548
public App(VBE vbe, IMessageBox messageBox,
4649
IRubberduckParser parser,
4750
IGeneralConfigService configService,
@@ -79,24 +82,39 @@ public App(VBE vbe, IMessageBox messageBox,
7982

8083
_projectsEventsConnectionPoint.Advise(sink, out _projectsEventsCookie);
8184

85+
_hookActions = new Dictionary<Type, Action>
86+
{
87+
{ typeof(MouseHook), HandleMouseMessage },
88+
{ typeof(KeyboardHook), HandleKeyboardMessage },
89+
};
90+
91+
8292
UiDispatcher.Initialize();
8393
}
8494

8595
private void _hooks_MessageReceived(object sender, HookEventArgs e)
8696
{
87-
if (sender is MouseHook)
97+
var hookType = sender.GetType();
98+
Action action;
99+
if (_hookActions.TryGetValue(hookType, out action))
88100
{
89-
_appMenus.EvaluateCanExecute(_parser.State);
101+
action.Invoke();
90102
}
91-
if (sender is KeyboardHook)
103+
}
104+
105+
private void HandleMouseMessage()
106+
{
107+
_appMenus.EvaluateCanExecute(_parser.State);
108+
}
109+
110+
private void HandleKeyboardMessage()
111+
{
112+
var pane = _vbe.ActiveCodePane;
113+
if (pane == null)
92114
{
93-
var pane = _vbe.ActiveCodePane;
94-
if (pane == null)
95-
{
96-
return;
97-
}
98-
_parser.State.OnParseRequested(this, pane.CodeModule.Parent);
115+
return;
99116
}
117+
_parser.State.OnParseRequested(this, pane.CodeModule.Parent);
100118
}
101119

102120
private void _configService_SettingsChanged(object sender, EventArgs e)
@@ -120,12 +138,13 @@ public void Startup()
120138

121139
Task.Delay(1000).ContinueWith(t =>
122140
{
141+
// run this on UI thread
123142
UiDispatcher.Invoke(() =>
124143
{
125144
_parser.State.OnParseRequested(this);
126145
_hooks.HookHotkeys();
127146
});
128-
}).ConfigureAwait(false);
147+
}, new StaTaskScheduler()).ConfigureAwait(false);
129148
}
130149

131150
#region sink handlers. todo: move to another class
@@ -271,6 +290,7 @@ async void sink_ProjectActivated(object sender, DispatcherEventArgs<VBProject> e
271290

272291
private void _stateBar_Refresh(object sender, EventArgs e)
273292
{
293+
// handles "refresh" button click on "Rubberduck" command bar
274294
_parser.State.OnParseRequested(sender);
275295
}
276296

RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,26 +78,26 @@ public ObservableCollection<CodeExplorerProjectViewModel> Projects
7878

7979
private void ParserState_StateChanged(object sender, EventArgs e)
8080
{
81-
Debug.WriteLine("CodeExplorerViewModel handles StateChanged...");
82-
IsBusy = _state.Status == ParserState.Parsing;
83-
if (_state.Status != ParserState.Ready)
84-
{
85-
return;
86-
}
87-
88-
Debug.WriteLine("Creating Code Explorer model...");
89-
var userDeclarations = _state.AllUserDeclarations
90-
.GroupBy(declaration => declaration.ProjectName)
91-
.Where(grouping => grouping.Key != null)
92-
.ToList();
93-
94-
if (userDeclarations.Any(grouping => grouping.All(declaration => declaration.DeclarationType != DeclarationType.Project)))
95-
{
96-
return;
97-
}
98-
99-
Projects = new ObservableCollection<CodeExplorerProjectViewModel>(userDeclarations.Select(grouping =>
100-
new CodeExplorerProjectViewModel(grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project), grouping)));
81+
//Debug.WriteLine("CodeExplorerViewModel handles StateChanged...");
82+
//IsBusy = _state.Status == ParserState.Parsing;
83+
//if (_state.Status != ParserState.Ready)
84+
//{
85+
// return;
86+
//}
87+
88+
//Debug.WriteLine("Creating Code Explorer model...");
89+
//var userDeclarations = _state.AllUserDeclarations
90+
// .GroupBy(declaration => declaration.ProjectName)
91+
// .Where(grouping => grouping.Key != null)
92+
// .ToList();
93+
94+
//if (userDeclarations.Any(grouping => grouping.All(declaration => declaration.DeclarationType != DeclarationType.Project)))
95+
//{
96+
// return;
97+
//}
98+
99+
//Projects = new ObservableCollection<CodeExplorerProjectViewModel>(userDeclarations.Select(grouping =>
100+
// new CodeExplorerProjectViewModel(grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project), grouping)));
101101
}
102102

103103
private void ParserState_ModuleStateChanged(object sender, Parsing.ParseProgressEventArgs e)

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
<Compile Include="Preprocessing\VBAPredefinedCompilationConstants.cs" />
171171
<Compile Include="Preprocessing\VBAPreprocessor.cs" />
172172
<Compile Include="Preprocessing\VBAPreprocessorVisitor.cs" />
173+
<Compile Include="StaTaskScheduler.cs" />
173174
<Compile Include="Symbols\CommentExtensions.cs" />
174175
<Compile Include="Symbols\DeclarationEventArgs.cs" />
175176
<Compile Include="Symbols\DeclarationFinder.cs" />
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Rubberduck.Common
10+
{
11+
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
12+
{
13+
private readonly List<Thread> _threads;
14+
private BlockingCollection<Task> _tasks;
15+
16+
public StaTaskScheduler()
17+
: this(1) { }
18+
19+
public StaTaskScheduler(int concurrencyLevel)
20+
{
21+
if (concurrencyLevel < 1)
22+
{
23+
throw new ArgumentOutOfRangeException("concurrencyLevel");
24+
}
25+
26+
_tasks = new BlockingCollection<Task>();
27+
_threads = Enumerable.Range(0, concurrencyLevel).Select(i =>
28+
{
29+
var thread = new Thread(() =>
30+
{
31+
foreach (var task in _tasks.GetConsumingEnumerable())
32+
{
33+
TryExecuteTask(task);
34+
}
35+
});
36+
thread.IsBackground = true;
37+
thread.SetApartmentState(ApartmentState.STA);
38+
return thread;
39+
}).ToList();
40+
41+
_threads.ForEach(thread => thread.Start());
42+
}
43+
44+
protected override void QueueTask(Task task)
45+
{
46+
_tasks.Add(task);
47+
}
48+
49+
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
50+
{
51+
// todo: figure out how to implement
52+
return false;
53+
}
54+
55+
protected override IEnumerable<Task> GetScheduledTasks()
56+
{
57+
return _tasks.ToArray();
58+
}
59+
60+
public override int MaximumConcurrencyLevel
61+
{
62+
get { return _threads.Count; }
63+
}
64+
65+
public void Dispose()
66+
{
67+
if (_tasks != null)
68+
{
69+
_tasks.CompleteAdding();
70+
foreach (var thread in _threads)
71+
{
72+
thread.Join();
73+
}
74+
75+
_tasks.Dispose();
76+
_tasks = null;
77+
}
78+
}
79+
}
80+
}

Rubberduck.VBEEditor/QualifiedModuleName.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public QualifiedModuleName(VBProject project)
1515
_componentName = null;
1616
_project = project;
1717
_projectName = project.ProjectName();
18-
//_contentHashCode = 0;
18+
_contentHashCode = 0;
1919
}
2020

2121
public QualifiedModuleName(VBComponent component)
@@ -27,17 +27,17 @@ public QualifiedModuleName(VBComponent component)
2727
_project = component == null ? null : component.Collection.Parent;
2828
_projectName = component == null ? string.Empty : component.ProjectName();
2929

30-
//_contentHashCode = 0;
31-
//if (component == null)
32-
//{
33-
// return;
34-
//}
35-
36-
//var module = component.CodeModule;
37-
//_contentHashCode = module.CountOfLines > 0
38-
// // ReSharper disable once UseIndexedProperty
39-
// ? module.get_Lines(1, module.CountOfLines).GetHashCode()
40-
// : 0;
30+
_contentHashCode = 0;
31+
if (component == null)
32+
{
33+
return;
34+
}
35+
36+
var module = component.CodeModule;
37+
_contentHashCode = module.CountOfLines > 0
38+
// ReSharper disable once UseIndexedProperty
39+
? module.get_Lines(1, module.CountOfLines).GetHashCode()
40+
: 0;
4141
}
4242

4343
/// <summary>
@@ -50,7 +50,7 @@ public QualifiedModuleName(string projectName, string componentName)
5050
_projectName = projectName;
5151
_componentName = componentName;
5252
_component = null;
53-
//_contentHashCode = 0;
53+
_contentHashCode = 0;
5454
}
5555

5656
public QualifiedMemberName QualifyMemberName(string member)
@@ -64,7 +64,8 @@ public QualifiedMemberName QualifyMemberName(string member)
6464
private readonly VBProject _project;
6565
public VBProject Project { get { return _project; } }
6666

67-
//private readonly int _contentHashCode;
67+
private readonly int _contentHashCode;
68+
public int ContentHashCode { get { return _contentHashCode; } }
6869

6970
private readonly string _projectName;
7071
public string ProjectName { get { return _projectName;} }

0 commit comments

Comments
 (0)