Partilhar via


Adicionar uma extensão do Language Server Protocol

O Language Server Protocol (LSP) é um protocolo comum, na forma de JSON RPC v2.0, usado para fornecer recursos de serviço de linguagem para vários editores de código. Usando o protocolo, os desenvolvedores podem escrever um único servidor de idioma para fornecer recursos de serviço de linguagem como IntelliSense, diagnóstico de erros, encontrar todas as referências e assim por diante, para vários editores de código que suportam o LSP. Tradicionalmente, os serviços de linguagem no Visual Studio podem ser adicionados usando arquivos de gramática TextMate para fornecer funcionalidades básicas, como realce de sintaxe ou escrevendo serviços de linguagem personalizados que usam o conjunto completo de APIs de extensibilidade do Visual Studio para fornecer dados mais ricos. Com o suporte do Visual Studio para LSP, há uma terceira opção.

serviço de protocolo de servidor de idioma no Visual Studio

Para garantir a melhor experiência de usuário possível, considere também implementar Language Configuration, que fornece processamento local de muitas das mesmas operações e, portanto, pode melhorar o desempenho de muitas das operações de editor específicas do idioma suportadas pelo LSP.

Protocolo do Servidor de Idiomas

implementação do protocolo de idiomas do servidor

Este artigo descreve como criar uma extensão do Visual Studio que usa um servidor de linguagem baseado em LSP. Ele pressupõe que você já desenvolveu um servidor de linguagem baseado em LSP e deseja apenas integrá-lo ao Visual Studio.

Para suporte dentro do Visual Studio, os servidores de idiomas podem se comunicar com o cliente (Visual Studio) por meio de qualquer mecanismo de transmissão baseado em fluxo, por exemplo:

  • Fluxos de entrada/saída padrão
  • Canalizações nomeadas
  • Soquetes (somente TCP)

A intenção do LSP e suporte para ele no Visual Studio é integrar serviços de linguagem que não fazem parte do produto Visual Studio. Não se destina a estender serviços de linguagem existentes (como C#) no Visual Studio. Para estender os idiomas existentes, consulte o guia de extensibilidade do serviço de idiomas (por exemplo, o "Roslyn" .NET Compiler Platform) ou consulte Estender o editor e os serviços de idioma.

Para obter mais informações sobre o protocolo em si, consulte a documentação aqui.

Para obter mais informações sobre como criar um servidor de idiomas de exemplo ou como integrar um servidor de idiomas existente no Visual Studio Code, consulte a documentação aqui.

Recursos suportados pelo Language Server Protocol

As tabelas a seguir mostram quais recursos LSP são suportados no Visual Studio:

Mensagem Tem suporte no Visual Studio
inicializar Sim
inicializado Sim
encerramento Sim
sair Sim
$/cancelRequest Sim
janela/mostrarMensagem Sim
janela/showMessageRequest Sim
janela/mensagem de registo Sim
telemetria/evento
cliente/registerCapability
cliente/desregistrarCapacidade
workspace/didChangeConfiguration Sim
espaço de trabalho/alterouArquivosMonitorados Sim
espaço de trabalho/símbolo Sim
workspace/executeCommand Sim
espaço de trabalho/aplicarEditar Sim
textDocument/publicarDiagnósticos Sim
textDocument/didOpen Sim
textDocument/didChange Sim
textDocument/willSave (guardar documento de texto)
textDocument/willSaveWaitUntil
documentoTexto/foiGuardado Sim
DocumentoDeTexto/fechou Sim
textoDocumento/preenchimento Sim
conclusão/resolução Sim
textDocument/pairar Sim
textDocument/signatureAjuda Sim
textDocument/referências Sim
textDocumento/documentoRealçar Sim
textDocument/documentSymbol Sim
textoDocumento/formatação Sim
documentoDeTexto/formataçãoDeIntervalo Sim
textDocument/onTypeFormatting
textDocument/definição Sim
textDocument/codeAction Sim
textDocument/codeLens
codeLens/resolver
DocumentoTexto/LigaçãoDocumento
linkDeDocumento/resolver
textDocument/renomear Sim

Introdução

Observação

A partir do Visual Studio 2017 versão 15.8, o suporte para o Common Language Server Protocol é incorporado ao Visual Studio. Se você criou extensões LSP usando a versão de visualização do Language Server Client VSIX, elas deixarão de funcionar quando você atualizar para a versão 15.8 ou superior. Você precisará fazer o seguinte para que suas extensões LSP funcionem novamente:

  1. Desinstale o Microsoft Visual Studio Language Server Protocol Preview VSIX.

    A partir da versão 15.8, cada vez que você executa uma atualização no Visual Studio, a visualização do VSIX é detetada e removida automaticamente.

  2. Atualize sua referência do Nuget para a versão não visualizada mais recente para pacotes LSP.

  3. Remova a dependência para o Microsoft Visual Studio Language Server Protocol Preview VSIX em seu manifesto VSIX.

  4. Verifique se o VSIX especifica o Visual Studio 2017 versão 15.8 Preview 3 como o limite inferior para o destino de instalação.

  5. Reconstruir e reimplantar.

Criar um projeto VSIX

Para criar uma extensão de serviço de idioma usando um servidor de idiomas baseado em LSP, primeiro verifique se você tem o de trabalho de desenvolvimento de extensão do Visual Studio instalado para sua instância do VS.

Em seguida, crie um novo projeto VSIX navegando até File>New Project>Visual C#>Extensibility>VSIX Project:

criar projeto vsix

Instalação do servidor de idiomas e do tempo de execução

Por padrão, as extensões criadas para oferecer suporte a servidores de linguagem baseados em LSP no Visual Studio não contêm os próprios servidores de linguagem ou os tempos de execução necessários para executá-los. Os desenvolvedores de extensões são responsáveis por distribuir os servidores de linguagem e os tempos de execução necessários. Existem várias formas de o fazer:

  • Os servidores de idiomas podem ser incorporados no VSIX como arquivos de conteúdo.
  • Crie um MSI para instalar o servidor de idiomas e/ou os tempos de execução necessários.
  • Fornecer instruções no Marketplace sobre como os utilizadores podem obter runtimes e servidores de linguagem.

Arquivos de gramática TextMate

O LSP não inclui especificações sobre como fornecer colorização de texto para idiomas. Para fornecer colorização personalizada para idiomas no Visual Studio, os desenvolvedores de extensão podem usar um arquivo de gramática TextMate. Para adicionar ficheiros de gramática ou tema personalizados do TextMate, siga estes passos:

  1. Crie uma pasta chamada "Gramáticas" dentro da sua extensão (ou pode ser qualquer nome que você escolher).

  2. Dentro da pasta Gramáticas, inclua qualquer *.tmlanguage, *.plist, *.tmthemeou qualquer outro *.json arquivos que pretende que forneçam colorização personalizada.

    Dica

    Um arquivo .tmtheme define como os âmbitos são mapeados para classificações do Visual Studio (identificadores de cor nomeados). Para orientação, pode-se fazer referência ao arquivo global .tmtheme no diretório <%ProgramFiles(x86)%\Microsoft Visual Studio\>versão<\>SKU\Common7\IDE\CommonExtensions\Microsoft\TextMate\Starterkit\Themesg.

  3. Crie um arquivo de .pkgdef e adicione uma linha semelhante a esta:

    [$RootKey$\TextMate\Repositories]
    "MyLang"="$PackageFolder$\Grammars"
    
  4. Clique com o botão direito do mouse nos arquivos e selecione Propriedades. Altere a ação Build para Content e altere a propriedade Include in VSIX para true.

Depois de concluir as etapas anteriores, uma pasta Gramáticas é adicionada ao diretório de instalação do pacote como uma fonte de repositório chamada 'MyLang' ('MyLang' é apenas um nome para desambiguação e pode ser qualquer string exclusiva). Todas as gramáticas (arquivos .tmlanguage) e arquivos de tema (arquivos .tmtheme) nesta pasta são considerados potenciais e substituem as gramáticas internas fornecidas com o TextMate. Se as extensões declaradas do arquivo de gramática corresponderem à extensão do arquivo que está sendo aberto, o TextMate intervirá.

Criar um cliente de linguagem simples

Interface principal - ILanguageClient

Depois de criar seu projeto VSIX, adicione o(s) seguinte(s) pacote(s) NuGet ao seu projeto:

  • Microsoft.VisualStudio.LanguageServer.Client

Observação

Quando você depende do pacote NuGet depois de concluir as etapas anteriores, os pacotes Newtonsoft.Json e StreamJsonRpc também são adicionados ao seu projeto. Não atualize esses pacotes, a menos que tenha certeza de que essas novas versões serão instaladas na versão do Visual Studio que a sua extensão tem como alvo. As assemblies não serão incluídas no seu VSIX; em vez disso, serão obtidas do diretório de instalação do Visual Studio. Se você estiver fazendo referência a uma versão mais recente dos assemblies do que a instalada na máquina de um usuário, sua extensão não funcionará.

Em seguida, você pode criar uma nova classe que implementa a interface ILanguageClient, que é a interface principal necessária para clientes de idioma que se conectam a um servidor de idiomas baseado em LSP.

Segue-se um exemplo:

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;
        }
    }
}

Os principais métodos que precisam ser implementados são OnLoadedAsync e ActivateAsync. OnLoadedAsync é chamado quando o Visual Studio carrega sua extensão e seu servidor de idiomas está pronto para ser iniciado. Nesse método, pode invocar o delegado StartAsync imediatamente para sinalizar que o servidor de linguagens deve ser iniciado, ou pode realizar lógica adicional e invocar StartAsync mais tarde. Para ativar seu servidor de idiomas, você deve chamar StartAsync em algum momento.

ActivateAsync é o método invocado ao chamar o delegado StartAsync. Ele contém a lógica para iniciar o servidor de idiomas e estabelecer conexão com ele. Um objeto de conexão que contém fluxos para gravar no servidor e ler a partir do servidor deve ser retornado. Quaisquer exceções lançadas aqui são capturadas e exibidas ao usuário por meio de uma mensagem da Barra de Informações no Visual Studio.

Ativação

Depois que sua classe de cliente de idioma for implementada, você precisará definir dois atributos para que ela defina como ela será carregada no Visual Studio e ativada:

  [Export(typeof(ILanguageClient))]
  [ContentType("bar")]

MEF

O Visual Studio usa MEF (Managed Extensibility Framework) para gerenciar seus pontos de extensibilidade. O atributo Export indica ao Visual Studio que essa classe deve ser coletada como um ponto de extensão e carregada no momento apropriado.

Para usar MEF, você também deve definir MEF como um ativo no manifesto VSIX.

Abra o designer de manifesto VSIX e navegue até a guia Ativos:

adicionar ativo MEF

Clique Novo para criar um novo ativo:

definir ativo MEF

  • Tipo: Microsoft.VisualStudio.MefComponent
  • Source: Um projeto na solução atual
  • Project: [O seu projeto]

Definição de tipo de conteúdo

Atualmente, a única maneira de carregar sua extensão de servidor de idioma baseada em LSP é por tipo de conteúdo de arquivo. Ou seja, ao definir sua classe de cliente de idioma (que implementa ILanguageClient), você precisará definir os tipos de arquivos que, quando abertos, farão com que sua extensão seja carregada. Se nenhum arquivo que corresponda ao seu tipo de conteúdo definido for aberto, sua extensão não será carregada.

Isto é feito através da definição de uma ou mais classes 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;
    }
}

No exemplo anterior, é criada uma definição de tipo de conteúdo para ficheiros que terminam na extensão de ficheiro .bar. A definição de tipo de conteúdo recebe o nome "bar" e deve derivar de CodeRemoteContentTypeName.

Depois de adicionar uma definição de tipo de conteúdo, você pode definir quando carregar sua extensão de cliente de idioma na classe de cliente de idioma:

    [ContentType("bar")]
    [Export(typeof(ILanguageClient))]
    public class BarLanguageClient : ILanguageClient
    {
    }

Adicionar suporte para servidores de linguagem LSP não requer que você implemente seu próprio sistema de projeto no Visual Studio. Os clientes podem abrir um único arquivo ou uma pasta no Visual Studio para começar a usar seu serviço de idioma. Na verdade, o suporte para servidores de linguagem LSP é projetado para funcionar apenas em cenários de pasta/arquivo abertos. Se um sistema de projeto personalizado for implementado, alguns recursos (como configurações) não funcionarão.

Funcionalidades avançadas

Configurações

O suporte para configurações personalizadas específicas do servidor de idioma está disponível, mas ainda está em processo de melhoria. As configurações são específicas para o que o servidor de idiomas suporta e geralmente controlam como o servidor de idiomas emite dados. Por exemplo, um servidor de idiomas pode ter uma configuração para o número máximo de erros relatados. Os autores da extensão definiriam um valor padrão, que pode ser alterado pelos usuários para projetos específicos.

Siga estas etapas abaixo para adicionar suporte para configurações à sua extensão de serviço de idioma LSP:

  1. Adicione um arquivo JSON (por exemplo, MockLanguageExtensionSettings.json) ao seu projeto que contém as configurações e seus valores padrão. Por exemplo:

    {
        "foo.maxNumberOfProblems": -1
    }
    
  2. Clique com o botão direito do mouse no arquivo JSON e selecione Propriedades. Altere a ação Build para "Content" e a propriedade "Include in VSIX' para true.

  3. Implemente ConfigurationSections e retorne a lista de prefixos para as configurações definidas no arquivo JSON (no Visual Studio Code, isso seria mapeado para o nome da seção de configuração em package.json):

    public IEnumerable<string> ConfigurationSections
    {
        get
        {
            yield return "foo";
        }
    }
    
  4. Adicione um arquivo .pkgdef ao projeto (adicione um novo arquivo de texto e altere a extensão do arquivo para .pkgdef). O arquivo pkgdef deve conter estas informações:

    [$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\[settings-name]]
    @="$PackageFolder$\[settings-file-name].json"
    

    Amostra:

    [$RootKey$\OpenFolder\Settings\VSWorkspaceSettings\MockLanguageExtension]
    @="$PackageFolder$\MockLanguageExtensionSettings.json"
    
  5. Clique com o botão direito do mouse no arquivo .pkgdef e selecione Propriedades. Altere a ação Build para Content e a propriedade Incluir no VSIX para true.

  6. Abra o ficheiro source.extension.vsixmanifest e adicione um ativo no separador de ativos:

    editar ativos do vspackage

    • Tipo: Microsoft.VisualStudio.VsPackage
    • Source: Arquivo no sistema de arquivos
    • Caminho: [Caminho para o arquivo de .pkgdef do]

Edição pelo usuário de configurações para um espaço de trabalho

  1. O usuário abre um espaço de trabalho contendo arquivos que seu servidor possui.

  2. O usuário adiciona um arquivo na pasta .vs chamada VSWorkspaceSettings.json.

  3. O usuário adiciona uma linha ao arquivo VSWorkspaceSettings.json para uma configuração fornecida pelo servidor. Por exemplo:

    {
        "foo.maxNumberOfProblems": 10
    }
    

Habilitar o rastreamento de diagnósticos

O rastreamento de diagnóstico pode ser ativado para gerar todas as mensagens entre o cliente e o servidor, o que pode ser útil ao solucionar problemas. Para habilitar o rastreamento de diagnóstico, faça o seguinte:

  1. Abra ou crie o arquivo de configurações do espaço de trabalho VSWorkspaceSettings.json (consulte "Edição de usuário de configurações para um espaço de trabalho").
  2. Adicione a seguinte linha no ficheiro de configurações json:
{
    "foo.trace.server": "Off"
}

Há três valores possíveis para a verbosidade do rastreamento:

  • "Desligado": rastreamento completamente desativado
  • "Mensagens": o rastreamento está ativado, mas apenas o nome do método e o ID da resposta são rastreados.
  • "Verbose": rastreamento ativado; Toda a mensagem RPC é rastreada.

Quando o rastreamento está ativado, o conteúdo é gravado em um arquivo no diretório \VisualStudio\LSP%temp%. O log segue o formato de nomenclatura [LanguageClientName]-[Datetime Stamp].log. Atualmente, o rastreamento só pode ser habilitado para cenários de pasta aberta. Abrir um único arquivo para ativar um servidor de idiomas não tem suporte ao rastreamento de diagnóstico.

Mensagens personalizadas

Existem APIs para facilitar a passagem e o recebimento de mensagens do servidor de idiomas que não fazem parte do Protocolo de Servidor de Idiomas padrão. Para gerir mensagens personalizadas, implemente interface ILanguageClientCustomMessage2 na sua classe de cliente de língua. A biblioteca VS-StreamJsonRpc é usada para transmitir mensagens personalizadas entre o cliente de linguagem e o servidor de linguagem. Como sua extensão de cliente de linguagem LSP é como qualquer outra extensão do Visual Studio, você pode decidir adicionar recursos adicionais (que não são suportados pelo LSP) ao Visual Studio (usando outras APIs do Visual Studio) em sua extensão por meio de mensagens personalizadas.

Receber mensagens personalizadas

Para receber mensagens personalizadas do servidor de idiomas, implemente a propriedade [CustomMessageTarget]((/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) em ILanguageClientCustomMessage2 e retorne um objeto que saiba como lidar com suas mensagens personalizadas. Exemplo abaixo:

(/dotnet/api/microsoft.visualstudio.languageserver.client.ilanguageclientcustommessage.custommessagetarget) propriedade em ILanguageClientCustomMessage2 e retornar um objeto que sabe como lidar com suas mensagens personalizadas. Exemplo abaixo:

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
        }
    }
}

Enviar mensagens personalizadas

Para enviar mensagens personalizadas para o servidor de idiomas, implemente o método AttachForCustomMessageAsync em ILanguageClientCustomMessage2. Este método é invocado quando o servidor de idiomas é iniciado e está pronto para receber mensagens. Um objeto JsonRpc é passado como um parâmetro, que você pode manter para enviar mensagens para o servidor de linguagem usando as APIs do VS-StreamJsonRpc. Exemplo abaixo:

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);
    }
}

Camada intermediária

Às vezes, um desenvolvedor de extensão pode querer intercetar mensagens LSP enviadas e recebidas do servidor de idiomas. Por exemplo, um desenvolvedor de extensão pode querer alterar o parâmetro de mensagem enviado para uma mensagem LSP específica ou modificar os resultados retornados do servidor de idiomas para um recurso LSP (por exemplo, conclusão). Quando isso é necessário, os desenvolvedores de extensões podem usar a API MiddleLayer para intercetar mensagens LSP.

Para intercetar uma mensagem específica, crie uma classe que implemente o interface de ILanguageClientMiddleLayer. Em seguida, implemente a interface ILanguageClientCustomMessage2 na sua classe de cliente de idioma e retorne uma instância do seu objeto na propriedade MiddleLayer. Exemplo abaixo:

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);
    }
  }
}

O recurso de camada intermediária ainda está em desenvolvimento e ainda não está abrangente.

Exemplo de extensão de servidor de idioma LSP

Para ver o código-fonte de uma extensão de exemplo usando a API do cliente LSP no Visual Studio, consulte VSSDK-Extensibility-Samples LSP sample.

FAQ

eu gostaria de criar um sistema de projeto personalizado para complementar meu servidor de linguagem LSP para fornecer suporte a recursos mais avançado no Visual Studio, como faço isso?

O suporte para servidores de linguagem baseados em LSP no Visual Studio depende do recurso de pasta aberta e foi projetado para não exigir um sistema de projeto personalizado. Você pode criar seu próprio sistema de projeto personalizado seguindo as instruções aqui, mas alguns recursos, como configurações, podem não funcionar. A lógica de inicialização padrão para servidores de idioma LSP é passar no local da pasta raiz da pasta que está sendo aberta no momento, portanto, se você usar um sistema de projeto personalizado, talvez seja necessário fornecer lógica personalizada durante a inicialização para garantir que o servidor de idiomas possa iniciar corretamente.

Como adiciono suporte ao depurador?

Forneceremos suporte para o protocolo de depuração comum em uma versão futura.

Se já houver um serviço de idioma compatível com VS instalado (por exemplo, JavaScript), ainda posso instalar uma extensão de servidor de idioma LSP que ofereça recursos adicionais (como linting)?

Sim, mas nem todos os recursos funcionarão corretamente. O objetivo final das extensões de servidor de idiomas LSP é habilitar serviços de linguagem não suportados nativamente pelo Visual Studio. Você pode criar extensões que oferecem suporte adicional usando servidores de linguagem LSP, mas alguns recursos (como o IntelliSense) não serão uma experiência suave. Em geral, é aconselhável que as extensões de servidor de linguagem LSP sejam usadas para fornecer novas experiências linguísticas, não estendendo as existentes.

Onde publico meu servidor de idiomas LSP VSIX concluído?

Consulte as instruções do Marketplace aqui.