Ich schreibe ein COM-Add-In, das eine IDE erweitert, die es dringend benötigt. Es gibt viele Funktionen, aber lassen Sie es uns für diesen Beitrag auf 2 eingrenzen:
- Es gibt einen Code - Explorer Toolwindow , dass zeigt eine Baumansicht , die die Benutzer navigieren Module und ihre Mitglieder können.
- Es gibt ein Code - Inspektionen Toolwindow , dass zeigt eine Datagridview , die die Benutzer navigieren Code Probleme können und automatisch beheben.
Beide Tools verfügen über eine Schaltfläche "Aktualisieren", mit der eine asynchrone Aufgabe gestartet wird, mit der der gesamte Code in allen geöffneten Projekten analysiert wird. Der Code-Explorer verwendet die Analyseergebnisse, um die Baumansicht zu erstellen , und die Code-Inspektionen verwenden die Analyseergebnisse, um Codeprobleme zu finden und die Ergebnisse in der Datagrid-Ansicht anzuzeigen .
Was ich versuche , hier zu tun, ist die Parse - Ergebnisse zwischen den Funktionen zu teilen, dass so , wenn die Code - Explorer Auffrischungen, dann ist der Code - Inspektionen weiß es und kann sich erneuern , ohne die Analyse der Arbeit wiederholen zu müssen , dass der Code - Explorer habe gerade .
Also habe ich meine Parser-Klasse zu einem Ereignisanbieter gemacht, bei dem sich die Funktionen registrieren können:
private void _parser_ParseCompleted(object sender, ParseCompletedEventArgs e)
{
Control.Invoke((MethodInvoker) delegate
{
Control.SolutionTree.Nodes.Clear();
foreach (var result in e.ParseResults)
{
var node = new TreeNode(result.Project.Name);
node.ImageKey = "Hourglass";
node.SelectedImageKey = node.ImageKey;
AddProjectNodes(result, node);
Control.SolutionTree.Nodes.Add(node);
}
Control.EnableRefresh();
});
}
private void _parser_ParseStarted(object sender, ParseStartedEventArgs e)
{
Control.Invoke((MethodInvoker) delegate
{
Control.EnableRefresh(false);
Control.SolutionTree.Nodes.Clear();
foreach (var name in e.ProjectNames)
{
var node = new TreeNode(name + " (parsing...)");
node.ImageKey = "Hourglass";
node.SelectedImageKey = node.ImageKey;
Control.SolutionTree.Nodes.Add(node);
}
});
}
Und es funktioniert. Das Problem, das ich habe, ist, dass ... es funktioniert - ich meine, wenn die Codeinspektionen aktualisiert werden, sagt der Parser dem Code-Explorer (und allen anderen): "Alter, jemand analysiert, was möchten Sie dagegen tun?" "" - und wenn das Parsen abgeschlossen ist, sagt der Parser seinen Zuhörern: "Leute, ich habe neue Analyseergebnisse für Sie, was möchten Sie dagegen tun?".
Lassen Sie mich Sie durch ein Beispiel führen, um das dadurch entstehende Problem zu veranschaulichen:
- Der Benutzer ruft den Code-Explorer auf, der dem Benutzer mitteilt, dass "Moment, ich arbeite hier". Benutzer arbeitet weiterhin in der IDE, der Code Explorer zeichnet sich neu, das Leben ist schön.
- Der Benutzer ruft dann die Code-Inspektionen auf, die dem Benutzer mitteilen, dass "Warte, ich arbeite hier". Der Parser teilt dem Code Explorer mit: "Alter, jemand analysiert, was möchten Sie dagegen tun?" - Der Code Explorer teilt dem Benutzer mit, "Moment, ich arbeite hier". Der Benutzer kann weiterhin in der IDE arbeiten, jedoch nicht im Code-Explorer navigieren, da dieser aktualisiert wird. Und er wartet auch darauf, dass die Code-Inspektionen abgeschlossen sind.
- Der Benutzer sieht ein Codeproblem in den Prüfergebnissen, die er behandeln möchte. Sie doppelklicken, um dorthin zu navigieren, bestätigen, dass ein Problem mit dem Code vorliegt, und klicken auf die Schaltfläche "Beheben". Das Modul wurde geändert und muss erneut analysiert werden, damit die Code-Inspektionen fortgesetzt werden können. Der Code Explorer teilt dem Benutzer mit, "Moment, ich arbeite hier", ...
Sehen Sie, wohin das führt? Ich mag es nicht und ich wette, Benutzer werden es auch nicht mögen. Was vermisse ich? Wie soll ich vorgehen, um Analyseergebnisse zwischen Features zu teilen, aber dem Benutzer trotzdem die Kontrolle darüber zu überlassen, wann das Feature seine Arbeit erledigen soll ?
Der Grund, den ich frage, ist, dass ich dachte, wenn ich die eigentliche Arbeit verschieben würde, bis der Benutzer sich aktiv für eine Aktualisierung entscheidet, und die Analyseergebnisse "zwischengespeichert" habe, sobald sie eingehen ... nun, dann würde ich eine Baumansicht aktualisieren und Suchen von Codeproblemen in einem möglicherweise veralteten Analyseergebnis ... was mich buchstäblich zu Punkt eins zurückbringt, wo jedes Feature mit seinen eigenen Analyseergebnissen arbeitet: Gibt es eine Möglichkeit, Analyseergebnisse zwischen Features auszutauschen und eine schöne UX zu haben?
Der Code ist c # , aber ich suche keinen Code, ich suche nach Konzepten .
VBAParser
von ANTLR generiert und gibt mir einen Analysebaum, aber die Funktionen verbrauchen das nicht. Der RubberduckParser
nimmt den Analysebaum, geht ihn durch und gibt ein aus VBProjectParseResult
, das Declaration
Objekte enthält , deren References
Auflösung vollständig ist - das ist es, was die Funktionen für die Eingabe benötigen. Also ja, es ist so ziemlich eine Alles-oder-Nichts-Situation. Das RubberduckParser
ist klug genug, um Module, die nicht geändert wurden, nicht erneut zu analysieren. Aber wenn es einen Engpass gibt, liegt das nicht am Parsen, sondern an den Code-Inspektionen.