Skip to content

Commit 6b62a78

Browse files
committed
Made numerous improvements for responsiveness and fixed bad logic
* Restructured GraphWorker code for readability and reliability * Added project for custom ParserTreeView control to replace the usual TreeView control * Updated solution Resharper settings * Increased default maximum node render count to 5000. This becomes more practical since users may want to load a huge near unusable graph, then use the "select parser rule" menu option to find a node in the giant graph and then further graph from there. * Modified logic to clear the graph window when the graph is too large * Replaced the TreeView control with the new lazy loading ParseTreeView control
1 parent f82317c commit 6b62a78

12 files changed

Lines changed: 428 additions & 85 deletions

Grun.Net.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<!-- If the number of graph nodes exceeds the maximum render count then the graph is simply not rendered. After a certain point the MSAGL
1717
graph canvas will lock up the UI while it is busy rendering and frankly a huge graph is sort of useless. It is better to graph subsections
1818
of a graph that has reached such a size. Your CPU will also thank you. -->
19-
<add key="MaximumNodeRenderCount" value="500"/>
19+
<add key="MaximumNodeRenderCount" value="5000"/>
2020
<!-- Heuristic Syntax Highlighting Color Settings -->
2121
<add key="DefaultTokenColor" value="Black"/>
2222
<add key="DefaultTokenBackgroundColor" value="Transparent"/>

Grun.Net.sln

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Images", "Images", "{78D248
2727
Grun.Net.png = Grun.Net.png
2828
EndProjectSection
2929
EndProject
30+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserTreeView", "ParserTreeView\ParserTreeView.csproj", "{B96D577C-E90A-4817-AA1C-3A211EFB83F0}"
31+
EndProject
3032
Global
3133
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3234
Debug|Any CPU = Debug|Any CPU
@@ -53,6 +55,10 @@ Global
5355
{8BD992FD-A3B3-4AF9-9371-5AA14DDFDA68}.Debug|Any CPU.Build.0 = Debug|Any CPU
5456
{8BD992FD-A3B3-4AF9-9371-5AA14DDFDA68}.Release|Any CPU.ActiveCfg = Release|Any CPU
5557
{8BD992FD-A3B3-4AF9-9371-5AA14DDFDA68}.Release|Any CPU.Build.0 = Release|Any CPU
58+
{B96D577C-E90A-4817-AA1C-3A211EFB83F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59+
{B96D577C-E90A-4817-AA1C-3A211EFB83F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
60+
{B96D577C-E90A-4817-AA1C-3A211EFB83F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
61+
{B96D577C-E90A-4817-AA1C-3A211EFB83F0}.Release|Any CPU.Build.0 = Release|Any CPU
5662
EndGlobalSection
5763
GlobalSection(SolutionProperties) = preSolution
5864
HideSolutionNode = FALSE
@@ -63,15 +69,4 @@ Global
6369
GlobalSection(ExtensibilityGlobals) = postSolution
6470
SolutionGuid = {A1CB1A18-09C5-4D7F-916D-2346D29A8563}
6571
EndGlobalSection
66-
GlobalSection(AutomaticVersions) = postSolution
67-
UpdateAssemblyVersion.Release|Any CPU = True
68-
UpdateAssemblyFileVersion.Release|Any CPU = True
69-
UpdateAssemblyInfoVersion.Release|Any CPU = True
70-
AssemblyVersionSettings.Release|Any CPU = None.None.DateStamp.IncrementWithResetOnIncrease
71-
AssemblyFileVersionSettings.Release|Any CPU = None.None.DateStamp.IncrementWithResetOnIncrease
72-
AssemblyInfoVersionSettings.Release|Any CPU = None.None.DateStamp.IncrementWithResetOnIncrease
73-
UpdatePackageVersion.Release|Any CPU = False
74-
AssemblyInfoVersionType.Release|Any CPU = SettingsVersion
75-
InheritWinAppVersionFrom.Release|Any CPU = None
76-
EndGlobalSection
7772
EndGlobal

Grun.Net.sln.DotSettings

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
22
<s:Int64 x:Key="/Default/CodeInspection/CleanCode/MaximumChainedReferences/@EntryValue">4</s:Int64>
33
<s:Int64 x:Key="/Default/CodeInspection/CleanCode/MaximumExpressionsInCondition/@EntryValue">3</s:Int64>
4+
<s:Int64 x:Key="/Default/CodeInspection/CleanCode/MaximumMethodParameters/@EntryValue">5</s:Int64>
5+
<s:Int64 x:Key="/Default/CodeInspection/CleanCode/MaximumMethodStatements/@EntryValue">30</s:Int64>
46
<s:Int64 x:Key="/Default/CodeInspection/CleanCode/MinimumMeaningfulMethodNameLength/@EntryValue">3</s:Int64>
57
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Dansko_002ESpyder_002EModels_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
68
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Standard_0020Cleanup/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Standard Cleanup"&gt;&lt;CSReorderTypeMembers&gt;True&lt;/CSReorderTypeMembers&gt;&lt;XMLReformatCode&gt;True&lt;/XMLReformatCode&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="False" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" /&gt;&lt;RemoveCodeRedundanciesVB&gt;True&lt;/RemoveCodeRedundanciesVB&gt;&lt;CssAlphabetizeProperties&gt;True&lt;/CssAlphabetizeProperties&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;JsReformatCode&gt;True&lt;/JsReformatCode&gt;&lt;JsFormatDocComments&gt;True&lt;/JsFormatDocComments&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;OptimizeReferenceCommentsTs&gt;True&lt;/OptimizeReferenceCommentsTs&gt;&lt;PublicModifierStyleTs&gt;True&lt;/PublicModifierStyleTs&gt;&lt;ExplicitAnyTs&gt;True&lt;/ExplicitAnyTs&gt;&lt;TypeAnnotationStyleTs&gt;True&lt;/TypeAnnotationStyleTs&gt;&lt;RelativePathStyleTs&gt;True&lt;/RelativePathStyleTs&gt;&lt;AsInsteadOfCastTs&gt;True&lt;/AsInsteadOfCastTs&gt;&lt;HtmlReformatCode&gt;True&lt;/HtmlReformatCode&gt;&lt;AspOptimizeRegisterDirectives&gt;True&lt;/AspOptimizeRegisterDirectives&gt;&lt;VBOptimizeImports&gt;True&lt;/VBOptimizeImports&gt;&lt;VBShortenReferences&gt;True&lt;/VBShortenReferences&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;&lt;CSFixBuiltinTypeReferences&gt;True&lt;/CSFixBuiltinTypeReferences&gt;&lt;CssReformatCode&gt;True&lt;/CssReformatCode&gt;&lt;VBReformatCode&gt;True&lt;/VBReformatCode&gt;&lt;VBFormatDocComments&gt;True&lt;/VBFormatDocComments&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;CSharpFormatDocComments&gt;True&lt;/CSharpFormatDocComments&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String>

GunWin/Graphing/GraphWorker.cs

Lines changed: 77 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void Graph(IParseTreeGrapher grapher, ITree tree, IList<string> parserRul
145145
_Settings.MaximumRenderShortDelay);
146146
var work = new GraphingWorkItem(tree, parserRules, grapher, nextRun);
147147
QueuedWork.Enqueue(work);
148-
_LastQueuedTime = DateTime.Now;
148+
_LastQueuedTime = DateTime.UtcNow;
149149
if (GraphingTask.IsCompleted)
150150
GraphingTask = new Task(GraphingWorkLoop);
151151
if (GraphingTask.Status != TaskStatus.Running)
@@ -187,7 +187,7 @@ private DateTime CalculateNextRunTime(
187187

188188
if (changed)
189189
OnThrottleStatusChanged();
190-
return DateTime.Now;
190+
return DateTime.UtcNow;
191191
}
192192

193193
var delay = Math.Min(maximumDelay, previousNodes * millisecondsPerNodeToDelay);
@@ -199,7 +199,7 @@ private DateTime CalculateNextRunTime(
199199
}
200200
if (changed)
201201
OnThrottleStatusChanged();
202-
return DateTime.Now + TimeSpan.FromMilliseconds(delay);
202+
return DateTime.UtcNow + TimeSpan.FromMilliseconds(delay);
203203
}
204204

205205
private void GraphingWorkLoop()
@@ -208,76 +208,95 @@ private void GraphingWorkLoop()
208208

209209
while (true)
210210
{
211-
bool changed;
212-
int workCount;
213211
DateTime lastQueued;
214-
lock (_Padlock)
215-
{
216-
if (currentRenderCount == 0)
217-
currentRenderCount = QueuedWork.Count;
218-
else
219-
currentRenderCount += QueuedWork.Count - 1;
220-
221-
workCount = currentRenderCount;
222-
if (workCount == 0)
223-
return;
224-
225-
lastQueued = _LastQueuedTime;
226-
}
212+
// Generate our render count and last queued time
213+
(currentRenderCount, lastQueued) = UpdateWorkloadValues(currentRenderCount);
227214

228-
if (workCount > _Settings.MinimumRenderCountToTriggerLongDelay && (DateTime.Now - lastQueued) < TimeSpan.FromMilliseconds(500))
215+
// check if we need to throttle with a long delay and if we do, execute a long delay before resuming
216+
if (currentRenderCount > _Settings.MinimumRenderCountToTriggerLongDelay && (DateTime.UtcNow - lastQueued) < TimeSpan.FromMilliseconds(500))
229217
{
230-
lock (_Padlock)
231-
{
232-
changed = _CurrentlyThrottling == 0 || _LongDelayActive == 0;
233-
_CurrentlyThrottling = 1;
234-
_LongDelayActive = 1;
235-
}
236-
if (changed)
237-
OnThrottleStatusChanged();
238-
Thread.Sleep(500);
218+
ExecuteLongDelay();
239219
continue;
240220
}
241221

242-
lock (_Padlock)
222+
// Now we build our graph or re-enqueue our last work item if we haven't reached the exact time to begin graphing
223+
currentRenderCount = EvaluateAndExecuteGraphWorkload();
224+
}
225+
}
226+
227+
private (int currentRenderCount, DateTime lastQueued) UpdateWorkloadValues(int currentRenderCount)
228+
{
229+
DateTime lastQueued;
230+
lock (_Padlock)
231+
{
232+
if (currentRenderCount == 0)
233+
currentRenderCount = QueuedWork.Count;
234+
else
235+
currentRenderCount += QueuedWork.Count - 1;
236+
237+
lastQueued = _LastQueuedTime;
238+
if (currentRenderCount == 0)
239+
return (currentRenderCount, lastQueued);
240+
}
241+
242+
return (currentRenderCount, lastQueued);
243+
}
244+
245+
private void ExecuteLongDelay()
246+
{
247+
bool changed;
248+
lock (_Padlock)
249+
{
250+
changed = _CurrentlyThrottling == 0 || _LongDelayActive == 0;
251+
_CurrentlyThrottling = 1;
252+
_LongDelayActive = 1;
253+
}
254+
if (changed)
255+
OnThrottleStatusChanged();
256+
Thread.Sleep(500);
257+
}
258+
259+
private int EvaluateAndExecuteGraphWorkload()
260+
{
261+
lock (_Padlock)
262+
{
263+
var changed = _LongDelayActive == 1;
264+
_LongDelayActive = 0;
265+
if (changed)
266+
OnThrottleStatusChanged();
267+
268+
// Sanity check ....just in case
269+
if (QueuedWork.Count == 0)
270+
return 0;
271+
272+
// We really only care about the last work item, so that's all we are keeping
273+
// However, we use the "GraphWhen" target date/time for the first entry for our check
274+
var work = QueuedWork.Dequeue();
275+
var graphWhen = work.GraphWhen;
276+
while (QueuedWork.Count != 0)
277+
work = QueuedWork.Dequeue();
278+
279+
// If we should delay longer, we enqueue the last item again for later evaluation
280+
if (DateTime.UtcNow < graphWhen)
243281
{
244-
changed = _LongDelayActive == 1;
245-
_LongDelayActive = 0;
246-
if (changed)
247-
OnThrottleStatusChanged();
248-
249-
// Sanity check ....just in case
250-
if (QueuedWork.Count == 0)
251-
return;
252-
253-
// We really only care about the last work item, so that's all we are keeping
254-
// However, we use the "GraphWhen" target date/time for the first entry for our check
255-
var work = QueuedWork.Dequeue();
256-
var graphWhen = work.GraphWhen;
257-
while (QueuedWork.Count != 0)
258-
work = QueuedWork.Dequeue();
259-
260-
// If we should delay longer, we enqueue the last item again for later evaluation
261-
if (DateTime.Now < graphWhen)
262-
{
263-
QueuedWork.Enqueue(work);
264-
continue;
265-
}
266-
267-
currentRenderCount = 0;
268-
var result = HandleGraphing(work);
269-
_PreviousNodeQty = result.NodeCount;
270-
OnGraphingFinished(result);
282+
QueuedWork.Enqueue(work);
283+
return QueuedWork.Count;
271284
}
285+
286+
var result = HandleGraphing(work);
287+
_PreviousNodeQty = result.NodeCount;
288+
OnGraphingFinished(result);
272289
}
290+
291+
return 0;
273292
}
274293

275294
/// <summary>
276295
/// Handles the actual graphing.
277296
/// </summary>
278297
/// <param name="work">The work item to graph.</param>
279298
/// <returns>A new <see cref="Graph" />.</returns>
280-
private GraphingResult HandleGraphing(GraphingWorkItem work)
299+
private static GraphingResult HandleGraphing(GraphingWorkItem work)
281300
{
282301
if (work.TreeGrapher == null || work.ParseTree == null)
283302
return new GraphingResult();
@@ -305,7 +324,7 @@ private void OnThrottleStatusChanged()
305324

306325
private void PostThrottleStatusChangedEvent(object state)
307326
{
308-
ThrottleStatusChanged?.Invoke(this, new EventArgs());
327+
ThrottleStatusChanged?.Invoke(this, EventArgs.Empty);
309328
}
310329
}
311330
}

GunWin/GunWin.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@
181181
<Project>{8bd992fd-a3b3-4af9-9371-5aa14ddfda68}</Project>
182182
<Name>Common</Name>
183183
</ProjectReference>
184+
<ProjectReference Include="..\ParserTreeView\ParserTreeView.csproj">
185+
<Project>{b96d577c-e90a-4817-aa1c-3a211efb83f0}</Project>
186+
<Name>ParserTreeView</Name>
187+
</ProjectReference>
184188
<ProjectReference Include="..\Utilities\Utilities.csproj">
185189
<Project>{4e020f1d-27bf-4853-8573-474d7edb4e72}</Project>
186190
<Name>Utilities</Name>

GunWin/VisualAnalyzer.Designer.cs

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

GunWin/VisualAnalyzer.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,7 @@ private void BuildParseTreeTreeViewGuide(ITree tree)
431431
return;
432432
}
433433

434-
var treeNode =
435-
new TreeNode(Trees.GetNodeText(tree, _Grammar.ParserRules)) { Tag = tree, Name = tree.GetHashCode().ToString() };
436-
ParseTreeView.Nodes.Add(treeNode);
437-
AddTreeBranchesAndLeaves(treeNode, tree);
434+
ParseTreeView.LoadParseTree(tree, _Grammar);
438435

439436
ParseTreeView.EndUpdate();
440437
ParseTreeView.ResumeLayout();
@@ -819,16 +816,11 @@ private void LoadSourceToolStripMenuItem_Click(object sender, EventArgs e)
819816

820817
private void Menu_GraphFromHere_Click(object sender, EventArgs e)
821818
{
822-
if (_Viewer.SelectedObject is Node node)
819+
if (_Viewer.SelectedObject is Node node && node.UserData is ITree target)
823820
{
824-
var treeNodes = ParseTreeView.Nodes.Find(node.UserData?.GetHashCode().ToString(), true);
825-
if (treeNodes.Length != 0)
826-
{
827-
var workingNode = treeNodes.First();
828-
ParseTreeView.SelectedNode = workingNode;
829-
RenderParseTreeGraph(workingNode.Tag as ITree, 0);
830-
ParseTreeView.Focus();
831-
}
821+
ParseTreeView.SelectTreeNode(target);
822+
RenderParseTreeGraph(target, 0);
823+
ParseTreeView.Focus();
832824
}
833825
}
834826

@@ -916,7 +908,10 @@ private void RenderParseTreeGraph(ITree tree, int? zoomFactor = null)
916908
var graph = _Grapher.CreateGraph(tree, _Grammar.ParserRules);
917909

918910
if (graph.Nodes.Count() > _Settings.MaximumNodeRenderCount)
911+
{
912+
_Viewer.Graph = null;
919913
return;
914+
}
920915

921916
graph.LayoutAlgorithmSettings = new SugiyamaLayoutSettings();
922917
_Viewer.SuspendLayout();

ParserTreeView/ParserTreeView.Designer.cs

Lines changed: 37 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)