Modifica del testo nell'editor
Le modifiche apportate a un documento di testo aperto nell'editor di Visual Studio possono derivare da interazioni utente in Visual Studio o modifiche a livello di codice dai servizi di linguaggio e da altre estensioni. L'estensione deve essere preparata per gestire le modifiche apportate al testo del documento in tempo reale.
Le estensioni in esecuzione all'esterno del processo IDE principale di Visual Studio usano modelli di progettazione asincroni per comunicare con il processo dell'IDE di Visual Studio. Ciò comporta l'uso di chiamate a metodi asincroni, come indicato dalla parola chiave async
in C# e rafforzato dal suffisso Async
sui nomi dei metodi. Asynchronicity è un vantaggio significativo nel contesto di un editor che dovrebbe essere reattivo alle azioni dell'utente. Una chiamata API sincrona tradizionale, se richiede più tempo del previsto, smetterà di rispondere all'input dell'utente, creando un blocco dell'interfaccia utente che dura fino al completamento della chiamata API. Le aspettative degli utenti delle applicazioni interattive moderne sono che gli editor di testo rimangono sempre reattivi e non li impediscono mai di funzionare. La presenza di estensioni asincrone è quindi essenziale per soddisfare le aspettative degli utenti.
Per ulteriori informazioni sulla programmazione asincrona, scopri di più su Programmazione asincrona con async e await.
Nel nuovo modello di estendibilità di Visual Studio, l'estensione è la seconda classe relativa all'utente: non può modificare direttamente l'editor o il documento di testo. Tutte le modifiche di stato sono asincrone e cooperative, con l'IDE di Visual Studio che esegue la modifica richiesta per conto dell'estensione. L'estensione può richiedere una o più modifiche in una versione specifica del documento o della visualizzazione testo, ma le modifiche apportate da un'estensione possono essere rifiutate, ad esempio se tale area del documento è stata modificata.
Le modifiche vengono richieste usando il metodo EditAsync()
in EditorExtensibility
.
Se si ha familiarità con le estensioni legacy di Visual Studio, ITextDocumentEditor
è quasi uguale ai metodi di modifica dello stato da ITextBuffer e ITextDocument e supporta la maggior parte delle stesse funzionalità.
MutationResult result = await this.Extensibility.Editor().EditAsync(
batch =>
{
var editor = document.AsEditable(batch);
editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);
Per evitare modifiche collocate in modo errato, le modifiche apportate dalle estensioni dell'editor vengono applicate come segue:
- L'estensione richiede una modifica, in base alla versione più recente del documento.
- Tale richiesta può contenere una o più modifiche di testo, modifiche alla posizione del cursore e così via. Qualsiasi tipo che implementa
IEditable
può essere modificato in una singola richiesta diEditAsync()
, inclusiITextViewSnapshot
eITextDocumentSnapshot
. Le modifiche vengono eseguite dall'editor, che può essere richiesto per una classe specifica tramiteAsEditable()
. - Le richieste di modifica vengono inviate all'IDE di Visual Studio, in cui ha esito positivo solo se l'oggetto modificato non è stato modificato dopo la versione in cui è stata effettuata la richiesta. Se il documento è stato modificato, la modifica potrebbe essere rifiutata, richiedendo all'estensione di tentare nuovamente sulla versione più recente. Il risultato dell'operazione di mutazione viene archiviato in
result
. - Le modifiche vengono applicate in modo atomico, ovvero senza interruzioni da altri thread in esecuzione. La procedura consigliata consiste nell'eseguire tutte le modifiche che devono verificarsi entro un intervallo di tempo ristretto in una singola chiamata
EditAsync()
, per ridurre la probabilità di comportamenti imprevisti derivanti dalle modifiche dell'utente o dalle azioni del servizio di linguaggio che si verificano tra le modifiche (ad esempio, le modifiche delle estensioni che si intersecano con Roslyn C# che sposta il cursore).
Modificare la posizione del cursore o selezionare il testo tramite un'estensione
La modifica di un documento di testo da un'estensione influisce in modo implicito sulla posizione del cursore. Ad esempio, l'inserimento di testo nel cursore sposta il cursore alla fine del testo inserito. Le estensioni possono anche usare ITextViewSnapshot.AsEditable().SetSelections()
per impostare il cursore in modo esplicito su una posizione diversa o effettuare selezioni di testo. Per illustrare, il codice seguente inserisce del testo, ma mantiene il cursore nella posizione originale:
await this.Extensibility.Editor().EditAsync(batch =>
{
var caret = textView.Selection.Extent.Start;
textView.Document.AsEditable(batch).Replace(textView.Selection.Extent, newGuidString);
textView.AsEditable(batch).SetSelections([new Selection(activePosition: caret, anchorPosition: caret, insertionPosition: caret)]);
},
cancellationToken);
Esecuzione simultanea
️ ⚠ | Le estensioni dell'editor possono talvolta essere eseguite contemporaneamente |
---|
La versione iniziale presenta un problema noto che può comportare l'esecuzione simultanea del codice di estensione dell'editor. È garantito che ogni metodo asincrono venga chiamato nell'ordine corretto, ma le continuazioni dopo il primo await
possono essere interleaved. Se l'estensione si basa sull'ordine di esecuzione, è consigliabile mantenere una coda di richieste in ingresso per mantenere l'ordine, fino a quando questo problema non viene risolto.
Per altre informazioni, vedere StreamJsonRpc Default Ordering and Concurrency.