J'écris un complément COM qui étend un IDE qui en a désespérément besoin. Il y a beaucoup de fonctionnalités impliquées, mais réduisons-le à 2 pour les besoins de ce post:
- Il existe une fenêtre d'outils Explorateur de code qui affiche une arborescence qui permet à l'utilisateur de parcourir les modules et leurs membres.
- Il existe une fenêtre d'outils Inspections de code qui affiche une vue de la grille de données qui permet à l'utilisateur de parcourir les problèmes de code et de les résoudre automatiquement.
Les deux outils ont un bouton "Actualiser" qui démarre une tâche asynchrone qui analyse tout le code dans tous les projets ouverts; l' Explorateur de code utilise les résultats de l'analyse pour créer l' arborescence et les inspections de code utilisent les résultats de l'analyse pour rechercher les problèmes de code et afficher les résultats dans sa vue de datagrid .
Ce que j'essaie de faire ici, c'est de partager les résultats de l'analyse entre les fonctionnalités, de sorte que lorsque l' explorateur de code est actualisé, les inspections de code le savent et puissent se rafraîchir sans avoir à refaire le travail d'analyse que l' explorateur de code vient de faire. .
Donc, ce que j'ai fait, j'ai fait de ma classe d'analyseur un fournisseur d'événements auquel les fonctionnalités peuvent s'inscrire:
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);
}
});
}
Et il fonctionne. Le problème que j'ai, c'est que ... ça marche - je veux dire, quand les inspections de code sont actualisées, l'analyseur dit à l'explorateur de code (et à tout le monde) "mec, analyse de quelqu'un, quoi que ce soit que vous voulez faire à ce sujet? " - et lorsque l'analyse est terminée, l'analyseur dit à ses auditeurs "les gars, j'ai de nouveaux résultats d'analyse pour vous, quoi que ce soit que vous vouliez faire à ce sujet?".
Permettez-moi de vous expliquer un exemple pour illustrer le problème que cela crée:
- L'utilisateur affiche l'explorateur de code, qui dit à l'utilisateur "attendez, je travaille ici"; l'utilisateur continue de travailler dans l'IDE, l'explorateur de code se redessine, la vie est belle.
- L'utilisateur fait ensuite apparaître les inspections de code, qui indiquent à l'utilisateur «attendez, je travaille ici»; l'analyseur dit à l'explorateur de code "mec, l'analyse de quelqu'un, qu'est-ce que vous voulez faire à ce sujet?" - l'Explorateur de code dit à l'utilisateur "attendez, je travaille ici"; l'utilisateur peut toujours travailler dans l'EDI, mais ne peut pas naviguer dans l'explorateur de code car il est rafraîchissant. Et il attend également la fin des inspections de code.
- L'utilisateur voit un problème de code dans les résultats d'inspection qu'il souhaite résoudre; ils double-cliquent dessus pour y accéder, confirment qu'il y a un problème avec le code et cliquent sur le bouton "Corriger". Le module a été modifié et doit être analysé de nouveau, de sorte que les inspections du code se poursuivent; l'explorateur de code dit à l'utilisateur "attendez, je travaille ici", ...
Vous voyez où cela va? Je n'aime pas ça, et je parie que les utilisateurs ne l'aimeront pas non plus. Qu'est-ce que je rate? Comment dois-je procéder pour partager les résultats d'analyse entre les fonctionnalités, tout en laissant à l'utilisateur le contrôle du moment où la fonctionnalité doit faire son travail ?
La raison pour laquelle je demande, c'est parce que je me suis dit que si je reportais le travail réel jusqu'à ce que l'utilisateur décide activement de rafraîchir, et "mis en cache" les résultats de l'analyse à mesure qu'ils entrent ... eh bien, je rafraîchirais un aperçu et localiser les problèmes de code dans un résultat d'analyse éventuellement périmé ... ce qui me ramène littéralement à la case départ, où chaque fonctionnalité fonctionne avec ses propres résultats d'analyse: est-il possible de partager les résultats d'analyse entre les fonctionnalités et d' avoir une belle UX?
Le code est c # , mais je ne cherche pas de code, je cherche des concepts .
VBAParser
est généré par ANTLR et me donne un arbre d'analyse, mais les fonctionnalités ne consomment pas cela. Le RubberduckParser
prend l'arbre d'analyse, le parcourt et émet un VBProjectParseResult
qui contient tous les Declaration
objets References
résolus - c'est ce que les fonctionnalités prennent pour la saisie .. alors oui, c'est à peu près une situation tout ou rien. Le RubberduckParser
est assez intelligent pour ne pas réanalyser les modules qui n'ont pas été modifiés cependant. Mais s'il y a un goulot d'étranglement, ce n'est pas avec l'analyse, c'est avec les inspections de code.