Cambio de texto en el editor
Las modificaciones, es decir, los cambios en un documento de texto abierto en el editor de Visual Studio pueden surgir de interacciones de usuario en Visual Studio o cambios mediante programación de servicios de lenguaje y otras extensiones. La extensión debe estar preparada para tratar los cambios en el texto del documento que se produce en tiempo real.
Las extensiones que se ejecutan fuera del proceso principal del IDE de Visual Studio usan patrones de diseño asincrónicos para comunicarse con el proceso del IDE de Visual Studio. Esto significa el uso de llamadas de método asincrónico, como se indica en la palabra clave async
en C# y reforzado por el sufijo Async
en los nombres de método. La asincronía es una ventaja significativa en el contexto de un editor que se espera que responda a las acciones del usuario. Una llamada api sincrónica tradicional, si tarda más de lo esperado, dejará de responder a la entrada del usuario, creando una inmovilización de la interfaz de usuario que dura hasta que se complete la llamada API. Los usuarios de aplicaciones interactivas modernas esperan que los editores de texto siempre sean receptivos y nunca les impidan trabajar. Por lo tanto, tener extensiones asincrónicas es esencial para satisfacer las expectativas del usuario.
Obtenga más información sobre la programación asincrónica en Programación asincrónica con Async y Await.
En el nuevo modelo de extensibilidad de Visual Studio, la extensión es la segunda clase relativa al usuario: no puede modificar directamente el editor ni el documento de texto. Todos los cambios de estado son asincrónicos y cooperativos, con el IDE de Visual Studio que realiza el cambio solicitado en nombre de la extensión. La extensión puede solicitar uno o varios cambios en una versión específica del documento o la vista de texto, pero se pueden rechazar los cambios de una extensión, como si ese área del documento haya cambiado.
Las modificaciones se solicitan mediante el método EditAsync()
en EditorExtensibility
.
Si está familiarizado con las extensiones heredadas de Visual Studio, ITextDocumentEditor
es casi igual que los métodos de cambio de estado de ITextBuffer y ITextDocument y admite la mayoría de las mismas funcionalidades.
MutationResult result = await this.Extensibility.Editor().EditAsync(
batch =>
{
var editor = document.AsEditable(batch);
editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);
Para evitar modificaciones mal colocadas, las modificaciones de las extensiones del editor se aplican de la siguiente manera:
- La extensión solicita que se realice una edición, en función de su versión más reciente del documento.
- Esa solicitud puede contener una o más modificaciones de texto, cambios en la posición del cursor, etc. Cualquier tipo que implemente
IEditable
se puede cambiar en una única solicitud deEditAsync()
, incluidosITextViewSnapshot
yITextDocumentSnapshot
. El editor realiza modificaciones, que se pueden solicitar en una clase específica a través deAsEditable()
. - Las solicitudes de edición se envían al IDE de Visual Studio, donde solo se realiza correctamente si el objeto que se va a mutar no ha cambiado desde la versión en la que se realizó la solicitud. Si el documento ha cambiado, se puede rechazar el cambio, lo que requiere que la extensión vuelva a intentarlo en una versión más reciente. El resultado de la operación de mutación se almacena en
result
. - Las modificaciones se aplican de forma atómica, lo que significa que sin interrupción de otros subprocesos en ejecución. El procedimiento recomendado consiste en realizar todos los cambios que deben producirse dentro de un período de tiempo limitado en una sola llamada a
EditAsync()
, para reducir la probabilidad de un comportamiento inesperado derivado de las ediciones del usuario o las acciones del servicio de lenguaje que se producen entre ediciones (por ejemplo, cuando las modificaciones de extensión se mezclan con Roslyn C# moviendo el cursor de inserción).
Cambiar la posición del cursor o seleccionar texto desde una extensión
La edición del documento de texto desde una extensión afecta implícitamente la posición del cursor. Por ejemplo, insertar texto en el cursor moverá el cursor al final del texto insertado. Las extensiones también pueden usar ITextViewSnapshot.AsEditable().SetSelections()
para establecer el cursor de texto explícitamente en una posición diferente o hacer selecciones de texto. Para ilustrarlo, el código siguiente insertaría el texto, pero mantenga el cursor en la posición original.
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);
Ejecución simultánea
⚠️ | A veces, las extensiones del editor se pueden ejecutar simultáneamente |
---|
La versión inicial tiene un problema conocido que puede dar lugar a la ejecución simultánea del código de extensión del editor. Se garantiza que cada método asincrónico se llame en el orden correcto, pero las continuaciones posteriores al primer await
pueden intercalarse. Si la extensión depende del orden de ejecución, considere mantener una cola de solicitudes para mantener el orden hasta que se corrija este problema.
Para obtener más información, consulte Ordenamiento y concurrencia predeterminados de StreamJsonRpc.