Sto scrivendo un componente aggiuntivo COM che estende un IDE che ne ha un disperato bisogno. Ci sono molte funzionalità coinvolte, ma riduciamola a 2 per il bene di questo post:
- C'è una finestra degli strumenti di Code Explorer che mostra una vista ad albero che consente all'utente di navigare tra i moduli e i loro membri.
- C'è una finestra degli strumenti di Code Inspections che visualizza una datagridview che consente all'utente di navigare tra i problemi del codice e risolverli automaticamente.
Entrambi gli strumenti hanno un pulsante "Aggiorna" che avvia un'attività asincrona che analizza tutto il codice in tutti i progetti aperti; il Code Explorer utilizza i risultati di parsing per costruire il treeview , e il codice ispezioni utilizza i risultati parse per trovare problemi di codice e visualizzare i risultati nella sua datagridview .
Quello che sto cercando di fare qui, è condividere i risultati dell'analisi tra le funzionalità, in modo che quando Code Explorer si aggiorna, allora Code Inspections ne sia a conoscenza e possa aggiornarsi senza dover ripetere il lavoro di analisi eseguito da Code Explorer .
Quindi, quello che ho fatto, ho reso la mia classe parser un provider di eventi a cui le funzionalità possono registrarsi:
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);
}
});
}
E funziona Il problema che sto riscontrando è che ... funziona - voglio dire, quando le ispezioni del codice vengono aggiornate, il parser dice all'esploratore del codice (e a tutti gli altri) "amico, qualcuno sta analizzando, cosa vuoi fare al riguardo? " - e al termine dell'analisi, il parser dice ai suoi ascoltatori "ragazzi, ho nuovi risultati di analisi per voi, cosa volete fare al riguardo?".
Lascia che ti spieghi un esempio per illustrare il problema che questo crea:
- L'utente visualizza Code Explorer, che dice all'utente "aspetta, sto lavorando qui"; l'utente continua a lavorare nell'IDE, il Code Explorer si ridisegna da solo, la vita è bella.
- L'utente visualizza quindi le ispezioni del codice, che indicano all'utente "aspetta, sto lavorando qui"; il parser dice a Code Explorer "amico, qualcuno sta analizzando, cosa vuoi fare al riguardo?" - Code Explorer dice all'utente "aspetta, sto lavorando qui"; l'utente può ancora lavorare nell'IDE, ma non può navigare in Esplora codici perché è rinfrescante. E sta aspettando anche il completamento delle ispezioni del codice.
- L'utente vede un problema di codice nei risultati dell'ispezione che desidera affrontare; fanno doppio clic per accedervi, confermano che c'è un problema con il codice e fanno clic sul pulsante "Correggi". Il modulo è stato modificato e deve essere riesaminato, quindi le ispezioni del codice procedono con esso; Code Explorer dice all'utente "aspetta, sto lavorando qui", ...
Vedi dove sta andando? Non mi piace e scommetto che neanche agli utenti piacerà. Cosa mi sto perdendo? Come devo fare per condividere i risultati dell'analisi tra le funzionalità, ma lasciare comunque all'utente il controllo di quando la funzionalità dovrebbe funzionare ?
Il motivo per cui lo sto chiedendo è perché ho pensato che se avessi posticipato il lavoro effettivo fino a quando l'utente non decidesse attivamente di aggiornare, e "memorizzato nella cache" i risultati dell'analisi man mano che entrano ... beh, allora aggiornerei un treeview e localizzare i problemi di codice in un risultato di analisi possibilmente stantio ... che mi riporta letteralmente al punto di partenza, dove ogni funzione funziona con i suoi risultati di analisi: esiste un modo per condividere i risultati di analisi tra funzionalità e avere una UX adorabile?
Il codice è c # , ma non cerco codice, cerco concetti .
VBAParser
è generato da ANTLR e mi dà un albero di analisi, ma le funzionalità non lo consumano. La RubberduckParser
prende l'albero di analisi, passeggiate, e le questioni di una VBProjectParseResult
che contiene Declaration
oggetti che hanno tutti i loro References
risolti - che di ciò che le caratteristiche assumono per l'ingresso .. Quindi sì, è più o meno una situazione di tutto-o-niente. È RubberduckParser
abbastanza intelligente da non analizzare nuovamente i moduli che non sono stati modificati. Ma se c'è un collo di bottiglia non è con l'analisi, è con le ispezioni del codice.