Agregar una extensión del protocolo de servidor de lenguaje
El Protocolo de servidor de lenguaje (LSP) es un protocolo común, en forma de JSON RPC v2.0, que se usa para proporcionar características del servicio de lenguaje a varios editores de código. Con el protocolo, los desarrolladores pueden escribir un único servidor de lenguaje para proporcionar características de servicio de lenguaje como IntelliSense, diagnóstico de errores, buscar todas las referencias, etc., en varios editores de código que admitan el LSP. Tradicionalmente, los servicios de lenguaje de Visual Studio se pueden agregar mediante archivos de gramática TextMate para proporcionar funcionalidades básicas, como el resaltado de sintaxis o la escritura de servicios de lenguaje personalizados que usan el conjunto completo de API de extensibilidad de Visual Studio para proporcionar datos más completos. Con la compatibilidad de Visual Studio con LSP, hay una tercera opción.
Para garantizar la mejor experiencia de usuario posible, considere también la posibilidad de implementar Configuración de lenguaje, que proporciona procesamiento local de muchas de las mismas operaciones y, por tanto, puede mejorar el rendimiento de muchas de las operaciones del editor específicas del lenguaje compatibles con el LSP.
Protocolo de servidor de lenguaje
En este artículo se describe cómo crear una extensión de Visual Studio que use un servidor de lenguaje basado en LSP. Se supone que ya ha desarrollado un servidor de lenguaje basado en LSP y que solo quiere integrarlo en Visual Studio.
Para obtener compatibilidad con Visual Studio, los servidores de lenguaje pueden comunicarse con el cliente (Visual Studio) a través de cualquier mecanismo de transmisión basado en secuencias, por ejemplo:
- Flujos de entrada y salida estándar
- Canalizaciones con nombre
- Sockets (solo TCP)
La intención del LSP y la compatibilidad con él en Visual Studio es incorporar servicios de lenguaje que no forman parte del producto de Visual Studio. No está pensado para ampliar los servicios de lenguaje existentes (como C#) en Visual Studio. Para ampliar los idiomas existentes, consulte la guía de extensibilidad del servicio de lenguaje (por ejemplo, la plataforma del compilador de .NET de "Roslyn") o consulte Ampliación del editor y los servicios de lenguaje.
Para obtener más información sobre el propio protocolo script, consulte la documentación aquí.
Para obtener más información sobre cómo crear un servidor de lenguaje de ejemplo o cómo integrar un servidor de lenguaje existente en Visual Studio Code, consulte la documentación aquí.
Características compatibles con el protocolo de servidor de lenguaje
En las tablas siguientes se muestran las características de LSP que se admiten en Visual Studio:
Mensaje | Compatibilidad en Visual Studio |
---|---|
initialize | sí |
inicializado | sí |
shutdown | sí |
exit | sí |
$/cancelRequest | sí |
window/showMessage | sí |
window/showMessageRequest | sí |
window/logMessage | sí |
telemetry/event | |
client/registerCapability | |
client/unregisterCapability | |
workspace/didChangeConfiguration | sí |
workspace/didChangeWatchedFiles | sí |
workspace/symbol | sí |
workspace/executeCommand | sí |
workspace/applyEdit | sí |
textDocument/publishDiagnostics | sí |
textDocument/didOpen | sí |
textDocument/didChange | sí |
textDocument/willSave | |
textDocument/willSaveWaitUntil | |
textDocument/didSave | sí |
textDocument/didClose | sí |
textDocument/completion | sí |
completion/resolve | sí |
textDocument/hover | sí |
textDocument/signatureHelp | sí |
textDocument/references | sí |
textDocument/documentHighlight | sí |
textDocument/documentSymbol | sí |
textDocument/formatting | sí |
textDocument/rangeFormatting | sí |
textDocument/onTypeFormatting | |
textDocument/definition | sí |
textDocument/codeAction | sí |
textDocument/codeLens | |
codeLens/resolve | |
textDocument/documentLink | |
documentLink/resolve | |
textDocument/rename | sí |
Introducción
Nota:
A partir de la versión 15.8 de Visual Studio 2017, la compatibilidad con el protocolo de servidor de lenguaje está integrada en Visual Studio. Si ha compilado extensiones LSP con la versión preliminar de VSIX del cliente del servidor de lenguaje, dejará de funcionar una vez que actualice a la versión 15.8 o posterior. Tendrá que hacer lo siguiente para que las extensiones de LSP funcionen de nuevo:
Desinstale la versión preliminar de VSIX del protocolo de servidor de lenguaje de Microsoft Visual Studio.
A partir de la versión 15.8, cada vez que realice una actualización en Visual Studio, la versión preliminar de VSIX se detecta y quita automáticamente.
Actualice la referencia de Nuget a la versión preliminar más reciente para los paquetes LSP.
Quite la dependencia a la versión preliminar de VSIX del protocolo de servidor de lenguaje de Microsoft Visual Studio en el manifiesto de VSIX.
Asegúrese de que VSIX especifica Visual Studio 2017, versión preliminar 3 de la versión 15.8 como límite inferior para el destino de instalación.
Vuelva a compilar e implementar.
Crear un proyecto de VSIX
Para crear una extensión de servicio de lenguaje mediante un servidor de lenguaje basado en LSP, primero asegúrese de que tiene instalada la carga de trabajo de desarrollo de extensiones de Visual Studio para la instancia de VS.
A continuación, cree un nuevo proyecto de VSIX; para ello, vaya a Archivo>Nuevo proyecto>Visual C#>Extensibilidad>Proyecto de VSIX:
Servidor de idioma e instalación en tiempo de ejecución
De forma predeterminada, las extensiones creadas para admitir servidores de lenguaje basados en LSP en Visual Studio no contienen los propios servidores de lenguaje ni los entornos de ejecución necesarios para ejecutarlos. Los desarrolladores de extensiones son responsables de distribuir los servidores de lenguaje y los entornos de ejecución necesarios. Existen varias formas de hacerlo:
- Los servidores de lenguaje se pueden incrustar en VSIX como archivos de contenido.
- Cree una MSI para instalar el servidor de lenguaje o los entornos de ejecución necesarios.
- Proporcione instrucciones sobre Marketplace que informe a los usuarios sobre cómo pueden obtener entornos de ejecución y servidores de lenguaje.
Archivos de gramática textMate
El LSP no incluye la especificación sobre cómo proporcionar coloración de texto para idiomas. Para proporcionar una coloración personalizada para los lenguajes en Visual Studio, los desarrolladores de extensiones pueden usar un archivo de gramática TextMate. Para agregar archivos personalizados de gramática o tema de TextMate, siga estos pasos:
Cree una carpeta denominada "Gramáticas" dentro de la extensión (o puede ser el nombre que elija).
Dentro de la carpeta Gramáticas, incluya cualquier archivo *.tmlanguage, *.plist, *.tmtheme o *.json que desee que proporcione coloración personalizada.
Sugerencia
Un archivo .tmtheme define cómo se asignan los ámbitos a las clasificaciones de Visual Studio (claves de color con nombre). A modo de orientación, puede consultar el archivo .tmtheme en el directorio %ProgramFiles(x86)%\Microsoft Visual Studio\<version>\<SKU>\Common7\IDE\CommonExtensions\Microsoft\TextMate\Starterkit\Themesg.
Cree un archivo .pkgdef y agregue una línea similar a esta:
[$RootKey$\TextMate\Repositories] "MyLang"="$PackageFolder$\Grammars"
Haga clic con el botón derecho en los archivos y seleccione Propiedades. Cambie la acción Crear a Contenido y cambie la propiedad Incluir en VSIX a verdadera.
Después de completar los pasos anteriores, se agrega una carpeta llamada Gramáticas al directorio de instalación del paquete como un origen de repositorio denominado "MyLang" ("MyLang" es solo un nombre para la desambiguación y puede ser cualquier cadena única). Todas las gramáticas (archivos .tmlanguage) y los archivos de tema (archivos .tmtheme) de este directorio se seleccionan como posibles y reemplazan las gramáticas integradas proporcionadas con TextMate. Si las extensiones declaradas del archivo de gramática coinciden con la extensión del archivo que se está abriendo, TextMate intervendrá.
Creación de un cliente de lenguaje sencillo
Interfaz principal - ILanguageClient
Después de crear el proyecto de VSIX, agregue los siguientes paquetes NuGet al proyecto:
Nota:
Cuando se toma una dependencia del paquete NuGet después de completar los pasos anteriores, también se agregan los paquetes Newtonsoft.Json y StreamJsonRpc al proyecto. No actualice estos paquetes a menos que esté seguro de que esas nuevas versiones se instalarán en la versión de Visual Studio a la que se dirige la extensión. Los ensamblados no se incluirán en VSIX; en su lugar, se recopilarán en el directorio de instalación de Visual Studio. Si hace referencia a una versión de los ensamblados más reciente que la instalada en el equipo de un usuario, la extensión no funcionará.
A continuación, puede crear una nueva clase que implemente la interfaz ILanguageClient, que es la interfaz principal necesaria para los clientes de lenguaje que se conectan a un servidor de lenguaje basado en LSP.
A continuación se muestra un ejemplo:
namespace MockLanguageExtension
{
[ContentType("bar")]
[Export(typeof(ILanguageClient))]
public class BarLanguageClient : ILanguageClient
{
public string Name => "Bar Language Extension";
public IEnumerable<string> ConfigurationSections => null;
public object InitializationOptions => null;
public IEnumerable<string> FilesToWatch => null;
public event AsyncEventHandler<EventArgs> StartAsync;
public event AsyncEventHandler<EventArgs> StopAsync;
public async Task<Connection> ActivateAsync(CancellationToken token)
{
await Task.Yield();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Server", @"MockLanguageServer.exe");
info.Arguments = "bar";
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = info;
if (process.Start())
{
return new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream);
}
return null;
}
public async Task OnLoadedAsync()
{
await StartAsync.InvokeAsync(this, EventArgs.Empty);
}
public Task OnServerInitializeFailedAsync(Exception e)
{
return Task.CompletedTask;
}
public Task OnServerInitializedAsync()
{
return Task.CompletedTask;
}
}
}
Los métodos principales que deben implementarse son OnLoadedAsync y ActivateAsync. Se llama a OnLoadedAsync cuando Visual Studio ha cargado la extensión y el servidor de lenguaje está listo para iniciarse. En este método, puede invocar el delegado StartAsync inmediatamente para indicar que se debe iniciar el servidor de lenguaje, o bien puede realizar lógica adicional e invocar StartAsync más adelante. Para activar el servidor de lenguaje, debe llamar a StartAsync en algún momento.
ActivateAsync es el método invocado finalmente mediante una llamada al delegado StartAsync . Contiene la lógica para iniciar el servidor de lenguaje y establecer la conexión con él. Se debe devolver un objeto de conexión que contenga secuencias para escribir en el servidor y leer desde el servidor. Las excepciones producidas aquí se detectan y se muestran al usuario a través de un mensaje de barra de información en Visual Studio.
Activación
Una vez implementada la clase de cliente de lenguaje, deberá definir dos atributos para que defina cómo se cargará en Visual Studio y se activará:
[Export(typeof(ILanguageClient))]
[ContentType("bar")]
MEF
Visual Studio usa MEF (Managed Extensibility Framework) para administrar sus puntos de extensibilidad. El atributo Export indica a Visual Studio que esta clase debe recopilarse como un punto de extensión y cargarse en el momento adecuado.
Para usar MEF, también debe definir MEF como activo en el manifiesto de VSIX.
Abra el diseñador de manifiestos de VSIX y vaya a la pestaña Activos:
Haga clic en Nuevo para crear un activo nuevo:
- Tipo: Microsoft.VisualStudio.MefComponent
- Origen: un proyecto de la solución actual
- Proyecto: [Su proyecto]
Definición de tipo de contenido
Actualmente, la única manera de cargar la extensión del servidor de lenguaje basado en LSP es por tipo de contenido de archivo. Es decir, al definir la clase cliente de lenguaje (que implementa ILanguageClient), deberá definir los tipos de archivos que, cuando se abran, hará que la extensión se cargue. Si no se abren archivos que coincidan con el tipo de contenido definido, la extensión no se cargará.
Esto se hace mediante la definición de una o varias clases ContentTypeDefinition
:
namespace MockLanguageExtension
{
public class BarContentDefinition
{
[Export]
[Name("bar")]
[BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
internal static ContentTypeDefinition BarContentTypeDefinition;
[Export]
[FileExtension(".bar")]
[ContentType("bar")]
internal static FileExtensionToContentTypeDefinition BarFileExtensionDefinition;
}
}
En el ejemplo anterior, se crea una definición de tipo de contenido para los archivos que terminan con la extensión de archivo .bar. La definición del tipo de contenido recibe el nombre "bar" y debe obtenerse de CodeRemoteContentTypeName.
Después de agregar una definición de tipo de contenido, puede definir cuándo cargar la extensión de cliente de lenguaje en la clase de cliente de lenguaje:
[ContentType("bar")]
[Export(typeof(ILanguageClient))]
public class BarLanguageClient : ILanguageClient
{
}
La adición de compatibilidad con servidores de lenguaje LSP no requiere que implemente su propio sistema de proyecto en Visual Studio. Los clientes pueden abrir un único archivo o una carpeta en Visual Studio para empezar a usar el servicio de lenguaje. De hecho, la compatibilidad con los servidores de lenguaje LSP está diseñada para funcionar solo en escenarios de archivos o carpetas abiertos. Si se implementa un sistema de proyecto personalizado, algunas características (como la configuración) no funcionarán.
Características avanzadas
Configuración
La compatibilidad con la configuración personalizada específica del servidor de lenguaje está disponible, pero todavía está en proceso de mejora. La configuración es específica de lo que admite el servidor de lenguaje y suele controlar la forma en que el servidor de lenguaje emite los datos. Por ejemplo, un servidor de lenguaje podría tener una configuración para el número máximo de errores notificados. Los autores de extensiones definirían un valor predeterminado, que los usuarios pueden cambiar para proyectos específicos.
Siga estos pasos para agregar compatibilidad con la configuración a la extensión del servicio de lenguaje LSP:
Agregue un archivo JSON (por ejemplo, MockLanguageExtensionSettings.json) al proyecto que contiene la configuración y sus valores predeterminados. Por ejemplo:
{ "foo.maxNumberOfProblems": -1 }
Haga clic con el botón derecho en el archivo JSON y seleccione Propiedades. Cambie la acción Crear a "Contenido" y cambie la propiedad "Incluir en VSIX" a verdadera.
Implemente ConfigurationSections y devuelva la lista de prefijos para la configuración definida en el archivo JSON (en Visual Studio Code, esto se asignaría al nombre de la sección de configuración en package.json):
public IEnumerable<string> ConfigurationSections { get { yield return "foo"; } }
Agregue un archivo .pkgdef al proyecto (agregue un nuevo archivo de texto y cambie la extensión de archivo a .pkgdef). El archivo pkgdef debe contener esta información:
[$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\[settings-name]] @="$PackageFolder$\[settings-file-name].json"
Sample:
[$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\MockLanguageExtension] @="$PackageFolder$\MockLanguageExtensionSettings.json"
Haga clic con el botón derecho en el archivo .pkgdef y seleccione Propiedades. Cambie la acción Crear a Contenido y cambie la propiedad Incluir en VSIX a verdadera.
Abra el archivo source.extension.vsixmanifest y agregue un activo en la pestaña Activo:
- Tipo: Microsoft.VisualStudio.VsPackage
- Origen: archivo del sistema de archivos
- Ruta de acceso: [Ruta de acceso al archivo .pkgdef]
Edición de usuarios de la configuración de un área de trabajo
El usuario abre un área de trabajo que contiene los archivos que posee el servidor.
El usuario agrega un archivo a la carpeta .vs llamado VSWorkspaceSettings.json.
El usuario agrega una línea al archivo VSWorkspaceSettings.json para una configuración que proporciona el servidor. Por ejemplo:
{ "foo.maxNumberOfProblems": 10 }
Habilitación del seguimiento de diagnósticos
El seguimiento de diagnósticos se puede habilitar para generar todos los mensajes entre el cliente y el servidor, lo que puede resultar útil al depurar problemas. Para habilitarlo, siga estos pasos:
- Abra o cree el archivo de configuración del área de trabajo VSWorkspaceSettings.json (consulte "Edición de usuarios de la configuración de un área de trabajo").
- Agregue la siguiente línea al archivo json de configuración:
{
"foo.trace.server": "Off"
}
Hay tres valores posibles para el nivel de detalle del seguimiento:
- "Desactivado": el seguimiento se ha desactivado por completo
- "Mensajes": el seguimiento está activado, pero solo se realiza el seguimiento del nombre del método y el identificador de respuesta.
- "Detallado": el seguimiento está activado; se realiza un seguimiento de todo el mensaje rpc.
Cuando se activa el seguimiento, el contenido se escribe en un archivo en el directorio %temp%\VisualStudio\LSP. El registro sigue el formato de nomenclatura [LanguageClientName]-[Datetime Stamp].log. Actualmente, el seguimiento solo se puede habilitar para escenarios de carpeta abierta. La apertura de un único archivo para activar un servidor de lenguaje no admite el seguimiento de diagnósticos.
Mensajes personalizados
Existen API para facilitar el traspaso y la recepción de mensajes hacia y desde el servidor de lenguaje que no forman parte del protocolo de servidor de lenguaje estándar. Para gestionar mensajes personalizados, implemente la interfaz ILanguageClientCustomMessage2 en la clase de cliente de lenguaje. La biblioteca VS-StreamJsonRpc se usa para transmitir mensajes personalizados entre el cliente de lenguaje y el servidor de lenguaje. Dado que la extensión de cliente del lenguaje LSP es igual que cualquier otra extensión de Visual Studio, puede decidir agregar características adicionales (que no son compatibles con el LSP) a Visual Studio (con otras API de Visual Studio) en la extensión a través de mensajes personalizados.
Recepción de mensajes personalizados
Para recibir mensajes personalizados del servidor de lenguaje, implemente la propiedad [CustomMessageTarget]((/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) property on ILanguageClientCustomMessage2 y devuelva un objeto que sepa cómo controlar los mensajes personalizados. A continuación se indica un ejemplo:
(/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) property on ILanguageClientCustomMessage2 y devuelva un objeto que sepa cómo controlar los mensajes personalizados. A continuación se indica un ejemplo:
internal class MockCustomLanguageClient : MockLanguageClient, ILanguageClientCustomMessage2
{
private JsonRpc customMessageRpc;
public MockCustomLanguageClient() : base()
{
CustomMessageTarget = new CustomTarget();
}
public object CustomMessageTarget
{
get;
set;
}
public class CustomTarget
{
public void OnCustomNotification(JToken arg)
{
// Provide logic on what happens OnCustomNotification is called from the language server
}
public string OnCustomRequest(string test)
{
// Provide logic on what happens OnCustomRequest is called from the language server
}
}
}
Envío de mensajes personalizados
Para enviar mensajes personalizados al servidor de lenguaje, implemente el método AttachForCustomMessageAsync en ILanguageClientCustomMessage2. Este método se invoca cuando se inicia el servidor de lenguaje y está listo para recibir mensajes. Un objeto JsonRpc se transfiere como parámetro, que puede mantener para enviar mensajes al servidor de lenguaje mediante las API VS-StreamJsonRpc. A continuación se indica un ejemplo:
internal class MockCustomLanguageClient : MockLanguageClient, ILanguageClientCustomMessage2
{
private JsonRpc customMessageRpc;
public MockCustomLanguageClient() : base()
{
CustomMessageTarget = new CustomTarget();
}
public async Task AttachForCustomMessageAsync(JsonRpc rpc)
{
await Task.Yield();
this.customMessageRpc = rpc;
}
public async Task SendServerCustomNotification(object arg)
{
await this.customMessageRpc.NotifyWithParameterObjectAsync("OnCustomNotification", arg);
}
public async Task<string> SendServerCustomMessage(string test)
{
return await this.customMessageRpc.InvokeAsync<string>("OnCustomRequest", test);
}
}
Capa intermedia
A veces, un desarrollador de extensiones puede querer interceptar los mensajes LSP enviados y recibidos del servidor de lenguaje. Por ejemplo, un desarrollador de extensiones puede querer modificar el parámetro de mensaje enviado para un mensaje LSP determinado o modificar los resultados que devuelve el servidor de lenguaje para una característica LSP (por ejemplo, finalizaciones). Cuando esto es necesario, los desarrolladores de extensiones pueden usar la API de middleLayer para interceptar los mensajes de LSP.
Para interceptar un mensaje determinado, cree una clase que implemente la interfaz ILanguageClientMiddleLayer. A continuación, implemente la interfaz ILanguageClientCustomMessage2 en la clase de cliente de lenguaje y devuelva una instancia del objeto en la propiedad MiddleLayer. A continuación se indica un ejemplo:
public class MockLanguageClient : ILanguageClient, ILanguageClientCustomMessage2
{
public object MiddleLayer => DiagnosticsFilterMiddleLayer.Instance;
private class DiagnosticsFilterMiddleLayer : ILanguageClientMiddleLayer
{
internal readonly static DiagnosticsFilterMiddleLayer Instance = new DiagnosticsFilterMiddleLayer();
private DiagnosticsFilterMiddleLayer() { }
public bool CanHandle(string methodName)
{
return methodName == "textDocument/publishDiagnostics";
}
public async Task HandleNotificationAsync(string methodName, JToken methodParam, Func<JToken, Task> sendNotification)
{
if (methodName == "textDocument/publishDiagnostics")
{
var diagnosticsToFilter = (JArray)methodParam["diagnostics"];
// ony show diagnostics of severity 1 (error)
methodParam["diagnostics"] = new JArray(diagnosticsToFilter.Where(diagnostic => diagnostic.Value<int?>("severity") == 1));
}
await sendNotification(methodParam);
}
public async Task<JToken> HandleRequestAsync(string methodName, JToken methodParam, Func<JToken, Task<JToken>> sendRequest)
{
return await sendRequest(methodParam);
}
}
}
La característica de capa intermedia está aún en fase de desarrollo y todavía no es completa.
Extensión de servidor de lenguaje LSP de ejemplo
Para ver el código fuente de una extensión de ejemplo mediante la API de cliente LSP en Visual Studio, consulte el ejemplo de LSP VSSDK-Extensibility-Samples.
Preguntas más frecuentes
Me gustaría crear un sistema de proyectos personalizado para complementar mi servidor de lenguaje LSP con el fin de ofrecer una mayor compatibilidad de funciones en Visual Studio. ¿Cómo puedo hacerlo?
La compatibilidad con servidores de lenguaje basados en LSP en Visual Studio se basa en la característica de carpeta abierta y está diseñada para no requerir un sistema de proyectos personalizado. Puede crear su propio sistema de proyectos personalizado siguiendo las instrucciones que se indican aquí, pero es posible que algunas características, como la configuración, no funcionen. La lógica de inicialización predeterminada para los servidores de lenguaje LSP consiste en transferir la ubicación de la carpeta raíz de la carpeta que se está abriendo, por lo que si usa un sistema de proyectos personalizado, es posible que tenga que proporcionar lógica personalizada durante la inicialización para asegurarse de que el servidor de lenguaje pueda iniciarse correctamente.
¿Cómo añado compatibilidad con el depurador?
Proporcionaremos compatibilidad con el protocolo de depuración común en una versión futura.
Si ya hay instalado un servicio de lenguaje compatible con VS (por ejemplo, JavaScript), ¿puedo instalar una extensión de servidor de lenguaje LSP que ofrezca características adicionales (como linting)?
Sí, pero no todas las características funcionarán correctamente. El objetivo final de las extensiones de servidor de lenguaje LSP es habilitar servicios de lenguaje no compatibles de forma nativa con Visual Studio. Puede crear extensiones que ofrezcan compatibilidad adicional con servidores de lenguaje LSP, pero algunas características (como IntelliSense) no tendrán una experiencia fluida. En general, se recomienda usar extensiones de servidor de lenguaje LSP para proporcionar nuevas experiencias de lenguaje, no para extender las existentes.
¿Dónde publico mi VSIX de servidor de lenguaje LSP completado?
Consulte las instrucciones de Marketplace aquí.