Estoy escribiendo un complemento COM que extiende un IDE que lo necesita desesperadamente. Hay muchas características involucradas, pero reduzcamos a 2 por el bien de esta publicación:
- Hay una ventana de herramientas de Code Explorer que muestra una vista de árbol que permite al usuario navegar por los módulos y sus miembros.
- Hay una ventana de herramientas de Inspecciones de código que muestra una vista de cuadrícula de datos que permite al usuario navegar por los problemas de código y corregirlos automáticamente.
Ambas herramientas tienen un botón "Actualizar" que inicia una tarea asincrónica que analiza todo el código en todos los proyectos abiertos; el explorador de código utiliza los resultados de análisis sintáctico para construir la vista de árbol , y la inspecciones de código utiliza los resultados de análisis sintáctico para encontrar problemas de código y mostrar los resultados en su DataGridView .
Lo que estoy tratando de hacer aquí es compartir los resultados de análisis entre las características, de modo que cuando el Explorador de códigos se actualice, las Inspecciones de código lo sepan y puedan actualizarse sin tener que rehacer el trabajo de análisis que acaba de hacer el Explorador de códigos .
Entonces, lo que hice, hice de mi clase de analizador un proveedor de eventos en el que las características pueden registrarse:
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);
}
});
}
Y funciona. El problema que tengo es que ... funciona. Quiero decir, cuando se actualizan las inspecciones de código, el analizador le dice al explorador de código (y a todos los demás) "amigo, alguien está analizando, ¿hay algo que quieras hacer al respecto? " - y cuando finaliza el análisis, el analizador le dice a sus oyentes "chicos, tengo nuevos resultados de análisis para ustedes, ¿qué quieren hacer al respecto?".
Permíteme mostrarte un ejemplo para ilustrar el problema que esto crea:
- El usuario muestra el Explorador de códigos, que le dice al usuario "espera, estoy trabajando aquí"; el usuario continúa trabajando en el IDE, el Code Explorer se vuelve a dibujar, la vida es hermosa.
- El usuario luego muestra las inspecciones de código, que le dicen al usuario "espera, estoy trabajando aquí"; el analizador le dice al Code Explorer "amigo, alguien está analizando, ¿hay algo que quieras hacer al respecto?" - el Explorador de códigos le dice al usuario "espera, estoy trabajando aquí"; el usuario aún puede trabajar en el IDE, pero no puede navegar por el Explorador de códigos porque es refrescante. Y también está esperando que se completen las inspecciones del código.
- El usuario ve un problema de código en los resultados de la inspección que desea abordar; hacen doble clic para navegar hasta él, confirman que hay un problema con el código y hacen clic en el botón "Reparar". El módulo se modificó y debe volver a analizarse, por lo que las inspecciones de código continúan con él; Code Explorer le dice al usuario "espera, estoy trabajando aquí", ...
¿Ves a dónde va esto? No me gusta, y apuesto a que a los usuarios tampoco les gustará. ¿Qué me estoy perdiendo? ¿Cómo debo compartir los resultados de análisis entre las funciones, pero aún así dejar al usuario en control de cuándo la función debe hacer su trabajo ?
La razón por la que pregunto es porque pensé que si posponía el trabajo real hasta que el usuario decidiera actualizar activamente, y "almacenaba en caché" los resultados del análisis a medida que entraban ... bueno, entonces estaría actualizando una vista de árbol y localizar problemas de código en un resultado de análisis posiblemente obsoleto ... que literalmente me lleva de vuelta al punto de partida, donde cada función funciona con sus propios resultados de análisis: ¿hay alguna manera de compartir los resultados de análisis entre funciones y tener un UX encantador?
El código es c # , pero no estoy buscando código, estoy buscando conceptos .
VBAParser
es generado por ANTLR y me da un árbol de análisis, pero las características no lo consumen. La RubberduckParser
toma del árbol de análisis, paseos, y emite una VBProjectParseResult
que contiene Declaration
los objetos que tienen toda su References
resolvieron - que de lo que toman las características para la entrada .. así que sí, es prácticamente una situación de todo o nada. Sin RubberduckParser
embargo, es lo suficientemente inteligente como para no volver a analizar módulos que no se han modificado. Pero si hay un cuello de botella no es con el análisis, sino con las inspecciones del código.