Plugin LSP (servidor de linguagem)¶
Inteligência de código movida pelo Language Server Protocol — traços ondulados de erro, navegação, dicas ao passar o mouse, autocompletar, ajuda de assinatura, formatação, localizar referências, renomear e ir para símbolo — para qualquer linguagem que tenha um servidor de linguagem. O editor conversa com o servidor por LSP; o plugin é o cliente. Quais servidores existem é definido por dados (um pequeno JSON por linguagem), então C++/clangd abaixo é apenas uma de várias definições incluídas.
O editor não inclui nem baixa servidores
Um servidor de linguagem é um programa separado que você instala uma vez. O MTE detecta um servidor instalado e o aponta para o seu projeto; ele nunca distribui um. Veja Obtendo um servidor de linguagem.
Recursos atuais¶
| Recurso | Como |
|---|---|
| Diagnósticos | Erros/avisos do servidor aparecem como sublinhados ondulados (vermelho = erro, âmbar = aviso, azul = informação, cinza = dica), atualizados enquanto você digita. |
| Ir para a definição | Coloque o cursor sobre um símbolo e pressione F12, ou use Pesquisar ▸ Navegação no código ▸ Ir para a definição. Salta para a definição, abrindo outro arquivo se necessário. |
| Localizar referências | Cursor sobre um símbolo → Shift+F12 (ou Pesquisar ▸ Navegação no código ▸ Localizar referências). Os resultados abrem em um painel inferior de Referências, agrupados por arquivo com uma prévia da linha de origem; duplo clique para saltar. |
| Dica ao passar o mouse | Deixe o ponteiro sobre um símbolo; um popup mostra o tipo/assinatura e a documentação dele (renderizados a partir do Markdown do servidor). |
| Autocompletar | Ctrl+Space pede complementos ao servidor e os funde no popup de autocompletar do editor (à frente das sugestões integradas de palavras-chave/buffer), filtrados enquanto você digita. |
| Ajuda de assinatura | Digitar o ( ou uma , de uma chamada mostra uma dica com a assinatura da função e o parâmetro ativo destacado; ) a dispensa. |
| Formatar o documento | Alt+Shift+F (⌃⌥F no macOS; ou Editar ▸ Formatar o documento) reformata o documento inteiro pelo servidor, em um único passo de desfazer. A configuração do próprio servidor rege o estilo (para o clangd, um arquivo .clang-format). |
| Localizar referências (listado acima) | — |
| Renomear o símbolo | Cursor sobre um símbolo → Shift+F6 (ou Editar ▸ Renomear o símbolo). Informe um nome novo; todos os usos são atualizados. Quando a renomeação abrange vários arquivos, você é solicitado a confirmar antes — cada arquivo é aberto, alterado e deixado modificado para você revisar e salvar. |
| Ir para símbolo (no arquivo) | Ctrl+Shift+O abre a paleta de comandos listando todos os símbolos do arquivo atual (funções, classes, métodos…); digite para filtrar, Enter salta. Cada linha mostra o tipo do símbolo e o contêiner dele. |
| Ir para o símbolo no espaço de trabalho | Ctrl+T pesquisa símbolos por todo o projeto enquanto você digita (é o servidor que faz a correspondência); Enter abre o arquivo no símbolo. |
Os seletores de ir para símbolo são os modos de símbolo da paleta de comandos — veja Paleta de comandos.
Os comandos ficam esmaecidos até haver um servidor em execução
Ir para a definição, Localizar referências, Formatar o documento e Renomear o símbolo só ficam habilitados quando um servidor de linguagem para a linguagem do arquivo atual está Pronto — e quando aquele servidor informou, no aperto de mãos inicial, que suporta a requisição. Em um arquivo sem servidor configurado, ou enquanto um está iniciando, reiniciando ou desistiu, as entradas de menu ficam esmaecidas em vez de não fazerem nada ao serem pressionadas. O indicador de status abaixo diz qual é o caso. Reiniciar os servidores de linguagem nunca fica esmaecido: é a saída para um servidor que desistiu.
Referências entre arquivos e renomeação precisam do índice do servidor
Localizar referências e Renomear só alcançam outros arquivos depois que o
servidor indexou o projeto. Para C/C++ isso significa um
compile_commands.json (veja abaixo) e o índice em segundo plano do clangd;
sem ele, eles operam apenas sobre o arquivo atual.
Por enquanto, renomear desfaz por arquivo
Uma renomeação em vários arquivos é aplicada um arquivo por vez, então cada arquivo é seu próprio passo de desfazer (a caixa de diálogo de confirmação diz isso). Revise as abas modificadas antes de salvar.
No menu de contexto do editor¶
Clique com o botão direito em um símbolo no texto e o menu oferece, abaixo dos comandos de edição, Ir para a definição, Localizar referências, Renomear o símbolo e Formatar o documento. Cada um só aparece quando o mesmo comando no menu principal funcionaria naquele momento — um servidor de linguagem para o arquivo está pronto e oferece suporte a ele e, para Renomear e Formatar, o documento não é somente leitura. Em um arquivo de texto simples, na margem à esquerda do texto ou enquanto o servidor está iniciando, nenhum deles aparece.
As entradas agem sobre o símbolo em que você clicou com o botão direito, não sobre o que está sob o cursor; o cursor e a seleção ficam onde estavam. Renomear propõe a seleção como nome antigo quando você clicou com o botão direito dentro dela e, caso contrário, a palavra sob o ponteiro. Formatar o documento sempre formata o documento inteiro. Um menu aberto pelo teclado age na posição do cursor.
Onde a plataforma mostra atalhos de teclado nos menus de contexto (Windows), cada entrada mostra o seu atalho — o que está em vigor, incluindo as suas próprias alterações no Mapeamento de atalhos. No macOS, os menus de contexto não mostram atalhos.
Como suas edições chegam ao servidor¶
Digitar não envia uma mensagem por tecla. As edições são agrupadas por uma fração de segundo e então enviadas como uma única alteração — e como um único intervalo editado em vez do arquivo inteiro, sempre que o servidor diz que pode aceitar um (a maioria pode). Assim, um arquivo grande custa algumas dezenas de bytes por rajada de digitação, em vez de uma cópia de si mesmo.
Tudo o que pergunta ao servidor sobre o texto — dica ao passar o mouse, ir para a definição, localizar referências, renomear, formatar, autocompletar, ajuda de assinatura — envia primeiro a edição pendente, para que uma resposta nunca se refira a uma versão que você já deixou para trás. Salvar um arquivo faz o mesmo.
Iniciar um servidor também não bloqueia o editor: o processo é lançado em segundo
plano e o segmento de status mostra … até ele terminar o aperto de mãos. Um
binário de servidor que trava na inicialização não custa a você nada além daquela
linguagem.
Um teto para quantos problemas são desenhados
São desenhados no máximo 2000 traços ondulados por documento. Além disso o arquivo fica ilegível de qualquer jeito, e cada marcador extra custa tempo real ao editor — então, quando um arquivo produz mais, os 2000 primeiros são exibidos e a barra de status diz Exibindo os primeiros 2000 de N problemas neste arquivo, em vez de deixar a contagem aparecer silenciosamente menor do que é. Isso costuma ser sinal de que o servidor está olhando o arquivo de forma errada: um banco de dados de compilação ausente, ou um arquivo gerado que não deveria compilar sozinho.
O indicador de status do servidor¶
A barra de status mostra um segmento compacto LSP: (à esquerda dos demais
segmentos de plugins) resumindo todos os servidores de linguagem relevantes para
os seus arquivos abertos:
| Glifo | Significado |
|---|---|
… |
Iniciando — o servidor foi lançado e está no aperto de mãos. |
✓ |
Pronto — atendendo requisições. |
↻n |
Reiniciando — o servidor parou inesperadamente; a tentativa automática de reinício número n está agendada. |
✗ |
Nenhum servidor instalado para esta linguagem. Instale um (veja abaixo) e depois use Reiniciar os servidores de linguagem. |
⚠ |
Desistiu — o servidor continuava falhando e os reinícios automáticos pararam. Só um reinício manual o revive. |
Uma linguagem pode carregar um qualificador curto depois do glifo — o servidor está em execução, e algo no seu projeto ainda limita o que ele pode responder. Apenas um é exibido por vez, o mais grave primeiro:
| Qualificador | Significado |
|---|---|
· server not responding |
Várias requisições seguidas ficaram sem resposta. O servidor está vivo, mas travado; use Mostrar o log do servidor de linguagem e depois Reiniciar os servidores de linguagem. O qualificador desaparece no momento em que o servidor responde qualquer coisa. |
· no compile database |
O servidor de C/C++ está em execução, mas só enxerga o arquivo que você tem aberto — veja Projetos C/C++ precisam de compile_commands.json. |
· no Cargo.toml, · no go.mod, · no tsconfig.json, … |
O projeto não tem nenhum dos arquivos de que este servidor precisa para entendê-lo como projeto. Ele ainda funciona no arquivo aberto; as respostas entre arquivos ficarão incompletas até o arquivo existir. O nome exato é o que o servidor mais quer — veja O que cada servidor precisa do seu projeto. |
O segmento aparece quando o primeiro documento com uma linguagem configurada é aberto, acompanha apenas as linguagens das quais você realmente tem documentos abertos — fechar o último arquivo de uma linguagem remove a entrada dela (reabrir um a traz de volta na hora) — e se oculta por completo quando não resta nenhum documento assim.
Pesquisar ▸ Navegação no código ▸ Mostrar o log do servidor de linguagem exibe a saída mais recente de todos os servidores em execução. É ali que um servidor se explica: uma cadeia de ferramentas ausente, um arquivo de configuração ilegível, um projeto que ele se recusou a carregar. A janela é normal e redimensionável — cada linguagem é um título que nomeia o servidor em execução para ela, o texto pode ser selecionado, Copiar põe o log inteiro na área de transferência, e o tamanho que você der à janela é lembrado.
Se um servidor falha¶
Um servidor de linguagem que termina inesperadamente é reiniciado
automaticamente com um atraso crescente (1 s, 2 s, 4 s… com teto de 30 s).
Enquanto isso acontece, o indicador mostra ↻n e uma notificação na barra de
status reporta a primeira falha. Depois de um reinício bem-sucedido, seus
documentos abertos são reanunciados ao servidor e os diagnósticos voltam sozinhos;
traços ondulados obsoletos do servidor morto são limpos imediatamente. A edição
nunca é bloqueada.
Depois de 5 tentativas fracassadas seguidas, o plugin desiste: o indicador
mostra ✗, uma notificação aponta você para as configurações, e a linguagem fica
apagada até você reiniciá-la manualmente. Um servidor que rodou bem por pelo menos
um minuto ganha um novo conjunto de tentativas quando falha mais tarde.
Reinício manual — qualquer um destes:
- Pesquisar ▸ Navegação no código ▸ Reiniciar os servidores de linguagem (sem atalho padrão; também disponível na paleta de comandos), ou
- o botão Examinar de novo / reiniciar os servidores em Preferências ▸ Servidor de linguagem.
Para ver por que um servidor está insatisfeito antes de reiniciá-lo, use Pesquisar ▸ Navegação no código ▸ Mostrar o log do servidor de linguagem.
Os dois desmontam todos os servidores, reexecutam a detecção com as configurações atuais e zeram o orçamento de falhas — use-os depois de instalar um servidor ausente ou de consertar um quebrado.
Obtendo um servidor de linguagem¶
Instale o servidor da sua linguagem e verifique se ele está no seu PATH (ou
defina um caminho explícito nas configurações). Se
nenhum for encontrado, o recurso simplesmente não faz nada para aquela linguagem —
o indicador de status mostra ✗ e o log registra
uma dica uma única vez, mas nada interrompe você.
O MTE inclui definições de servidor (não os servidores) para muitas linguagens, então a maioria só precisa que o servidor esteja instalado — sem editar JSON. As definições incluídas cobrem C/C++, Objective-C, Python, Rust, Go, TypeScript, JavaScript, C#, Java, Kotlin, Swift, HTML, CSS/SCSS/Less, JSON, YAML e scripts de shell.
| Linguagem | Servidor | Onde obtê-lo |
|---|---|---|
| C/C++ | clangd | winget install LLVM.LLVM (Windows), o componente "C++ Clang tools" no instalador do Visual Studio, brew install llvm (macOS), ou o pacote clang-tools-extra da sua distribuição. |
| Python | pyright ou pylsp | npm i -g pyright (precisa do Node.js), ou pip install python-lsp-server (precisa apenas do Python). |
| TypeScript/JS | typescript-language-server | npm i -g typescript-language-server typescript. |
| Rust | rust-analyzer | rustup component add rust-analyzer. |
| Go | gopls | go install golang.org/x/tools/gopls@latest. |
| C# | csharp-ls ou OmniSharp | dotnet tool install -g csharp-ls (uma única ferramenta dotnet, tentada primeiro), ou baixe uma versão do OmniSharp. |
| Java | jdtls (Eclipse JDT Language Server) | brew install jdtls (macOS), ou descompacte uma versão e ponha o bin dela no seu PATH. |
Verifique em um terminal, por exemplo clangd --version ou where clangd /
which clangd. Para uma linguagem da qual o MTE não inclui definição, acrescente
uma como descrito em Acrescentando uma linguagem.
Python: pyright ou pylsp¶
O Python tem duas definições incluídas, e o OctoEdit executa a que estiver realmente instalada:
- pyright (
pyright-langserver) é tentado primeiro. Ele é um pacote npm, então precisa do Node.js:npm i -g pyright. - pylsp (
python-lsp-server) é usado quando o pyright não é encontrado. Ele é um pacote pip e precisa apenas do Python:pip install python-lsp-server.
Se os dois estiverem instalados, o pyright vence. Há uma única linha de
configurações para Python (um sinalizador de ativação, uma substituição de
caminho), e ela vale para qualquer servidor que seja usado — definir um caminho
explícito para um executável pylsp executa o pylsp com os argumentos de
inicialização dele, não os do pyright. Mostrar o log do servidor de linguagem
nomeia o servidor que está de fato em execução.
Vários servidores para uma linguagem
Este é um mecanismo geral, não um caso especial do Python: uma linguagem pode
ter qualquer número de definições incluídas, ordenadas por um campo
priority, e a primeira cujo executável for encontrado na sua máquina é a que
inicia. C# funciona do mesmo jeito — csharp-ls primeiro, OmniSharp
depois — porque os dois recebem argumentos de inicialização diferentes e apenas
um deles pode estar certo.
Java: o espaço de trabalho do próprio servidor¶
O jdtls se recusa a iniciar sem um diretório de espaço de trabalho gravável
próprio (-data). O OctoEdit fornece um automaticamente, por projeto, sob a
pasta de dados do plugin:
Você nunca precisa criá-lo nem nomeá-lo. Apagar a pasta é seguro — o jdtls a reconstrói, ao custo de uma reindexação.
Configurando no Windows¶
Uma máquina Windows recém-instalada geralmente não tem nenhum de clangd,
cmake, ninja, node ou python no PATH. Esta seção diz de onde cada um vem
e como verificar. Normalmente você não precisa editar o PATH — o OctoEdit também
procura nos diretórios de ecossistema
listados abaixo.
| Você quer | Instale | Onde ele fica |
|---|---|---|
| clangd (C/C++) | winget install LLVM.LLVM |
C:\Program Files\LLVM\bin\clangd.exe |
| cmake e ninja | O componente "C++ CMake tools for Windows" no Instalador do Visual Studio | …\Microsoft Visual Studio\2022\<edition>\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin e …\CMake\Ninja — não estão no seu PATH, mas são alcançáveis pelo ambiente de desenvolvimento do Visual Studio (veja abaixo). Um winget install Kitware.CMake / winget install Ninja-build.Ninja independente os coloca no PATH. |
| pyright (Python) | winget install OpenJS.NodeJS.LTS e depois npm i -g pyright |
%APPDATA%\npm\pyright-langserver.cmd |
| pylsp (Python, sem precisar do Node) | Python da Microsoft Store ou do python.org, e depois pip install python-lsp-server |
%LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts\pylsp.exe (Store) ou %APPDATA%\Python\Python3*\Scripts\pylsp.exe |
Verificando o que está visível. Em um Prompt de Comando ou PowerShell normal:
O where procura apenas no seu PATH. Uma ferramenta que ele não encontra ainda
pode ser achada pelo OctoEdit, porque a busca também cobre os diretórios de
ecossistema acima — os diretórios de scripts do Python, em particular, nunca estão
no PATH. Se uma linguagem continuar em ✗ depois de instalar o servidor dela,
use Pesquisar ▸ Navegação no código ▸ Reiniciar os servidores de linguagem, que
reexecuta a busca inteira.
A geração do banco de dados de compilação roda dentro do ambiente de
desenvolvimento do Visual Studio. Quando o OctoEdit executa o CMake por você
(abaixo), ele primeiro localiza o Visual Studio — via VSINSTALLDIR ou, se não,
com vswhere.exe — e envolve a chamada no VsDevCmd.bat -arch=x64 daquela
instalação. É isso que põe cl, o SDK do Windows e o próprio cmake/ninja do
Visual Studio no caminho para aquele único comando, de modo que o editor não
precisa deles no seu PATH de forma alguma. Sem o Visual Studio (uma máquina
só com clang ou com MinGW) a chamada é feita simplesmente, no próprio ambiente do
editor, e o log diz isso; você então precisa de cmake e ninja acessíveis por
conta própria, e de um compilador que o CMake consiga identificar.
Regerando sob demanda. Pesquisar ▸ Navegação no código ▸ Gerar o banco de
dados de compilação… executa a mesma geração a qualquer momento — inclusive
quando um banco de dados já existe (ele é reconfigurado no lugar) e quando você
antes respondeu Não perguntar para este projeto. A entrada está sempre
disponível — quando não consegue gerar, ela diz por quê na barra de status
(nenhum documento C/C++, nenhuma pasta de projeto, nenhum CMakeLists.txt na raiz
do projeto, nenhum cmake, ou nenhum gerador aqui capaz de exportar um) em vez de
ficar esmaecida por um motivo que você não consegue ver.
Onde a resposta de "não perguntar" é guardada. Não perguntar para este
projeto é guardada por raiz de projeto em %APPDATA%\7-bits\OctoEdit.ini, sob
plugins/org.mte.lsp/noCompileDbPrompt/<hash> (o caminho do projeto vira hash
porque um caminho não é uma chave de configurações válida). Executar Gerar o banco
de dados de compilação… a limpa para aquele projeto.
Onde o OctoEdit procura um servidor¶
Você não deveria precisar configurar nada. Depois de instalar um servidor, abrir uma pasta e um arquivo-fonte basta. Em ordem, o editor tenta:
- um caminho explícito definido por você nas configurações — que manda: se ele não resolver, a linguagem fica apagada em vez de recorrer silenciosamente a outra coisa;
- seu
PATH, para o comando do servidor e cada alias conhecido (clangd-20,clangd-19, …); - os locais de instalação da definição do servidor para o seu sistema operacional;
- uma lista integrada de diretórios de ecossistema.
| Diretórios de ecossistema pesquisados | |
|---|---|
| Windows | o prefixo global do npm e %APPDATA%\npm, %LOCALAPPDATA%\Microsoft\WinGet\Links, %USERPROFILE%\.cargo\bin, %USERPROFILE%\go\bin e %LOCALAPPDATA%\go\bin, %USERPROFILE%\.dotnet\tools, %ProgramFiles%\LLVM\bin, %ProgramFiles%\nodejs, e os diretórios de scripts do Python por usuário: %APPDATA%\Python\Python3*\Scripts, %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts (Python da Microsoft Store) e %LOCALAPPDATA%\Programs\Python\Python3*\Scripts |
| macOS | /opt/homebrew/bin e /opt/homebrew/opt/llvm/bin (o clangd do Homebrew fica no segundo — ele nunca é vinculado ao primeiro), /usr/local/bin, /usr/local/opt/llvm/bin, ~/.cargo/bin, ~/go/bin, ~/.local/bin, ~/.npm-global/bin, ~/.dotnet/tools, ~/Library/Python/3.*/bin |
| Linux | /usr/local/bin, /usr/lib/llvm*/bin, Linuxbrew, e os mesmos ~/.cargo/bin, ~/go/bin, ~/.local/bin, ~/.npm-global/bin, ~/.dotnet/tools |
As entradas com * são curingas de verdade: o diretório de versão que o Python
cria (Python313, 3.13, ou o …Python.3.13_qbz5n2kfra8p0 da Store) é comparado
com o que realmente está no disco, do mais novo para o mais antigo. É ali que o
pip install python-lsp-server coloca o pylsp, e é por isso que instalá-lo não
exige mexer no PATH.
macOS: iniciar pelo Finder versus por um terminal
Um aplicativo iniciado pelo Finder ou pelo Dock não herda o PATH do
perfil do seu shell — o macOS lhe dá um mínimo
(/usr/bin:/bin:/usr/sbin:/sbin). Homebrew, Cargo, Go e npm seriam todos
invisíveis. Por isso o OctoEdit pergunta ao seu shell de login qual é o
PATH dele e procura ali também, e entrega o ambiente resultante ao servidor
que inicia — então um servidor instalado por qualquer uma dessas ferramentas é
encontrado, seja qual for a forma como você inicia o editor.
O servidor é iniciado uma vez por linguagem e encerrado com o editor.
Projetos C/C++ precisam de compile_commands.json¶
O clangd só entende seu código com precisão quando conhece as opções de
compilação, a partir de um banco de dados de compilação
(compile_commands.json). Sem um, o clangd recorre a adivinhações e os recursos
entre arquivos (localizar referências, renomear) ficam limitados ao arquivo
aberto. O clangd é iniciado de qualquer jeito.
Um projeto C/C++ conta como configurado quando tem qualquer um destes:
- um
compile_commands.jsonna raiz do projeto ou em um dos diretórios de build que o OctoEdit varre (build/,Build/,out/,out/build/,cmake-build-debug/,cmake-build-release/,.mte-compile-commands/); - um
compile_flags.txtna raiz do projeto; - um arquivo de configuração
.clangdna raiz do projeto.
O clangd lê os dois últimos por conta própria, então nada é reportado sobre eles.
Quando nenhum deles está presente — para todo projeto C/C++, qualquer que
seja o sistema de build — o segmento de status mostra · no compile database e
uma mensagem da barra de status diz isso uma vez. Nada bloqueia; nenhuma caixa de
diálogo interrompe sua digitação.
Deixando o OctoEdit gerá-lo (projetos CMake)¶
Se a raiz do projeto tem um CMakeLists.txt e um CMake que de fato produziria
um banco de dados, isso é oferecido a você uma vez por projeto:
- Gerar — executa o CMake em segundo plano, apenas a configuração: nada é
compilado e seus próprios diretórios de build ficam intocados. O resultado vai
para
<project>/.mte-compile-commands/. Em caso de sucesso, o clangd é reiniciado contra o novo banco de dados; em caso de falha, as últimas linhas do log do CMake são exibidas, junto com o comando exato que foi tentado, para que você possa repeti-lo. - Como fazer isso manualmente — mostra aquele mesmo comando sem executá-lo.
- Não perguntar para este projeto — lembrado por raiz de projeto.
Tanto a janela de "como fazer manualmente" quanto a de falha mostram a linha de comando exata em uma caixa de código selecionável, acima de um único botão Copiar cuja dica diz o que ele leva: o comando sozinho, ou o comando junto com o trecho final do log do CMake quando há um. A janela de falha é redimensionável e lembra o tamanho que você lhe dá — cada uma dessas janelas lembra o próprio tamanho, de modo que ampliar o log do servidor não faz uma janela de instruções de duas linhas abrir igualmente grande.
Você não está limitado a essa única oferta: Pesquisar ▸ Navegação no código ▸ Gerar o banco de dados de compilação… inicia a mesma geração quando você quiser — depois de acrescentar arquivos, depois de mudar opções de build, ou depois de ter respondido Não perguntar para este projeto (o que ela limpa). Um banco de dados existente é reconfigurado no lugar. A entrada está sempre disponível; quando não consegue gerar, ela diz por quê na barra de status.
Suas predefinições vêm primeiro. Se o projeto tem um CMakePresets.json (ou um
CMakeUserPresets.json), o OctoEdit configura com uma das suas predefinições em
vez de inventar uma linha de comando —
cmake --preset <name> -B <project>/.mte-compile-commands -DCMAKE_EXPORT_COMPILE_COMMANDS=ON.
Assim, o gerador, o conjunto de ferramentas e o bloco environment da predefinição
(um QT6_DIR, um caminho de SDK) são os que o projeto já usa, e o CMake os aplica
sozinho. Predefinições ocultas, as que uma condition exclui no seu sistema
operacional, ou as que configuram com um gerador incapaz de exportar são puladas;
um nome contendo debug é preferido. Seu próprio diretório de build nunca é
tocado — o editor sempre redireciona a saída com -B.
No Windows, o CMake é executado dentro de um ambiente de desenvolvimento do
Visual Studio. Um editor iniciado pelo Explorador ou pelo menu Iniciar não tem
cl no PATH, e o CMake então se contentaria silenciosamente com qualquer outro
compilador que encontrasse — inclusive o clang.exe que vem dentro de uma
instalação do Visual Studio, que logo falha em configurações específicas do MSVC.
Por isso o OctoEdit localiza o Visual Studio com o vswhere e envolve a chamada em
VsDevCmd.bat -arch=x64. Se não houver Visual Studio instalado (uma máquina MinGW
ou só com clang), a chamada é feita simplesmente e o log diz isso.
Uma tentativa fracassada anterior é limpa antes de uma nova: o CMakeCache.txt
dela fixaria, do contrário, o compilador que falhou. Um diretório que já contém um
compile_commands.json funcional é reconfigurado no lugar, nunca apagado.
Por que a oferta às vezes não aparece
O CMAKE_EXPORT_COMPILE_COMMANDS só é respeitado pelos geradores Ninja e
Makefile; o gerador do Visual Studio o ignora e não escreve banco de dados
algum. Então, no Windows, para um projeto sem nenhuma predefinição utilizável,
a oferta aparece apenas quando o ninja está no seu PATH. Quando as únicas
predefinições aplicáveis de um projeto são do Visual Studio e também não há
Ninja, o OctoEdit diz qual predefinição ficou no caminho, em vez de se oferecer
para executar algo que não poderia funcionar.
Gerando você mesmo (CMake)¶
O CMAKE_EXPORT_COMPILE_COMMANDS é respeitado apenas pelos geradores Ninja e
Makefile — o gerador do Visual Studio o ignora (ele não produz
compile_commands.json nem com o sinalizador ligado). Então gere o banco de dados
com Ninja, em um diretório dedicado, separado daquele em que você
normalmente compila: o CMake se recusa a reconfigurar um diretório de build
existente com outro gerador, então um projeto que você costuma compilar com o
Visual Studio precisa do próprio diretório Ninja.
Este é um passo apenas de configuração (não é preciso um build completo). A partir da raiz do projeto:
.mte-compile-commands/é um dos diretórios que o MTE varre, então ocompile_commands.jsonresultante é encontrado automaticamente. Qualquer diretório varrido também serve (build/,out/,cmake-build-*, ou a raiz do projeto) — apenas mantenha-o separado de um diretório configurado com outro gerador.- Execute-o a partir de um ambiente em que o projeto de fato se configure: o
compilador certo no
PATH(por exemplo, um x64 Native Tools Command Prompt no Windows) e quaisquer variáveis de que seu projeto precise (comoQT6_DIRem um projeto Qt). Se ocmakenão encontrar seu compilador ou SDK, o banco de dados acaba vazio ou sem caminhos de inclusão, e o clangd não indexará bem. - Reabra a pasta depois. O log não deve mais dizer "no compile_commands.json"; dê ao clangd um momento para construir o índice em segundo plano antes que referências/renomeação abranjam vários arquivos.
Outros sistemas de build: Bear (bear -- make), compiledb, Meson, Bazel e
outros podem produzir um compile_commands.json que o plugin encontrará.
Qual servidor atende qual arquivo¶
Quem decide é o nome do arquivo. Cada definição de servidor lista as extensões
que atende, e a primeira definição que reivindica a extensão de um arquivo é a que
inicia. A correspondência ignora maiúsculas e minúsculas, e só o último ponto
conta — Deploy.Prod.SH é um script de shell.
Isso é deliberadamente independente da coloração de sintaxe. Desligar a coloração, ou abrir um arquivo maior que o limite de tamanho da coloração, não custa mais também o servidor de linguagem.
O id do colorizador ainda é um recurso de reserva
Se nenhuma definição reivindicar a extensão, o OctoEdit recorre ao id de linguagem que o mecanismo de coloração atribuiu. Isso mantém funcionando uma definição escrita à mão que nomeia uma linguagem mas não lista extensões.
O nome que é informado ao servidor é uma segunda coisa, separada: o LSP tem o
próprio vocabulário de ids de linguagem, e vários deles não coincidem com os do
OctoEdit. Um arquivo .sh é anunciado como shellscript, um .scss como scss,
um .jsx como javascriptreact, um .mm como objective-cpp. Servidores que se
comportam de forma diferente por linguagem — o servidor de CSS, o de TypeScript —
precisam que isso esteja certo.
| Extensão | Atendida por | Anunciada como |
|---|---|---|
.cpp .cxx .cc .h .hpp .hh .hxx .ipp .inl |
clangd | cpp |
.c |
clangd | c |
.m / .mm |
clangd | objective-c / objective-cpp |
.sh .bash .zsh .ksh |
bash-language-server | shellscript |
.css / .scss / .less |
vscode-css-language-server | css / scss / less |
.ts .mts .cts / .tsx |
typescript-language-server | typescript / typescriptreact |
.js .mjs .cjs / .jsx |
typescript-language-server | javascript / javascriptreact |
.json / .jsonc .json5 |
vscode-json-language-server | json / jsonc |
O .h é reivindicado pela definição de C/C++, e não pela de Objective-C — as duas
executam o clangd, que decide sozinho o que um cabeçalho contém.
O que cada servidor precisa do seu projeto¶
Vários servidores só funcionam direito quando um arquivo específico está na raiz do projeto. Quando ele falta, o indicador de status diz isso em vez de fingir que está tudo bem:
| Linguagem | Quer | Sem ele |
|---|---|---|
| Rust | Cargo.toml |
o rust-analyzer não carregará o crate de forma alguma. |
| Go | go.mod |
o gopls não consegue resolver o módulo. |
| TypeScript | tsconfig.json (ou package.json) |
respostas de âmbito de projeto ficam indisponíveis. |
| JavaScript | jsconfig.json (ou package.json) |
o mesmo que acima. |
| Python (pyright) | pyproject.toml / pyrightconfig.json / setup.py |
o pyright ainda funciona; ele só usa padrões para raízes de importação e rigor. |
| Java | pom.xml / build.gradle |
o jdtls não consegue montar um classpath. |
| C/C++ | compile_commands.json |
veja a seção acima. |
Acrescentando uma linguagem¶
Os servidores são descritos por arquivos JSON que o plugin carrega na
inicialização a partir de <editor>/lsp-servers/*.json, além da
sua própria pasta. Cada entrada mapeia uma
linguagem ao comando dela, mais dicas de descoberta:
{
"language": "cpp",
"languageId": "cpp",
"languageIds": { ".c": "c" },
"command": "clangd",
"aliases": ["clangd-20", "clangd-19"],
"args": ["--background-index", "--log=verbose"],
"extensions": [".cpp", ".h", ".hpp", ".c"],
"projectMarkers": [],
"searchDirs": ["${LLVM}/bin", "${ProgramFiles}/LLVM/bin"],
"searchDirsMac": ["/opt/homebrew/opt/llvm/bin"],
"searchDirsLinux": ["/usr/lib/llvm-20/bin"],
"docsAnchor": "cpp-clangd",
"compileCommandsArg": "--compile-commands-dir=${dir}"
}
languageé o id próprio do OctoEdit para a linguagem — a chave pela qual a página de configurações, o segmento de status e a conexão são agrupados.command/aliasessão os nomes de executável tentados noPATH.extensionsé o mapeamento principal de arquivo para linguagem (veja acima). Inclua o ponto.argsleva um elemento do array por argumento.["--background-index", "--log=verbose"]passa dois argumentos;["--background-index --log=verbose"]passa um argumento que por acaso contém um espaço, o que todo servidor rejeita — e como ele então termina de imediato, o resultado parece um laço de falhas em vez de um erro de digitação. O OctoEdit avisa sobre esse formato no log de diagnóstico quando carrega seu arquivo.languageId(opcional) é o id enviado ao servidor nodidOpen; por padrão ele assume o valor delanguage. Use-o quando o nome da especificação LSP diferir do nosso (bash→shellscript,objc→objective-c).languageIds(opcional) substituilanguageIdpor extensão, para um único servidor que atende várias linguagens da especificação.projectMarkers(opcional) são os nomes de arquivo que o servidor quer na raiz do projeto. Quando nenhum deles está lá, o segmento de status dizsem <first marker>; ele nunca interrompe o servidor.searchDirsé a lista de locais de instalação do Windows;searchDirsMacesearchDirsLinuxsão os equivalentes por plataforma. As três expandem${VAR}, e as listas POSIX também expandem um~inicial. Uma entrada cujas variáveis não estão definidas é pulada em vez de virar um caminho sem sentido.argspode usar dois marcadores:${dataDir}, a pasta de dados gravável do plugin, e${rootHash}, um id curto e estável do projeto atual. É assim que o jdtls recebe-data <dir>. Um marcador que não pode ser resolvido é deixado literalmente no argumento, em vez de expandido para nada.compileCommandsArg(opcional) é acrescentado ao final, com${dir}substituído pelo diretório do banco de dados localizado — é assim que o clangd é apontado para ocompile_commands.json.priority(opcional,0por padrão) ordena várias definições da mesma linguagem: o número mais baixo é tentado primeiro, e a primeira definição cujo executável for encontrado é a que inicia. É assim que o Python recebe o pyright (priority: 0) com o pylsp (priority: 10) como reserva.
Suas próprias definições de servidor¶
As definições incluídas ficam dentro do diretório de instalação, que não é seu para editar (Program Files no Windows, um pacote de aplicativo assinado no macOS). Coloque as suas ao lado delas: Preferências ▸ Servidor de linguagem ▸ Abrir a pasta de definições de servidor do usuário cria e abre
Todo *.json nela é carregado depois do conjunto incluído, e:
- um arquivo cujo
languageecommandcorrespondem a uma definição incluída a substitui — é assim que você altera os argumentos do clangd ou acrescenta um diretório de busca; - qualquer outra coisa é acrescentada — um segundo servidor para uma linguagem que distribuímos, ou uma linguagem para a qual o OctoEdit não distribui nada.
Um arquivo que não é JSON válido, ou que não tem language ou command, é pulado
e reportado no log de diagnóstico, em vez de custar a você uma linguagem em
silêncio.
As definições são lidas uma única vez, na inicialização: reinicie o editor depois de editá-las (o botão Varrer de novo / reiniciar servidores reexecuta a busca, não o carregamento).
{
"language": "zig",
"command": "zls",
"extensions": [".zig", ".zon"],
"projectMarkers": ["build.zig"],
"searchDirs": ["${LOCALAPPDATA}/zls"],
"searchDirsMac": ["/opt/homebrew/bin", "~/.local/bin"],
"searchDirsLinux": ["~/.local/bin"]
}
Qual pasta é entregue ao servidor¶
Um servidor de linguagem precisa saber onde o projeto está: o rust-analyzer não
carrega um crate sem isso, o gopls precisa da raiz do módulo, o pyright lê o
pyrightconfig.json dela e o clangd procura o banco de dados dele ali.
- Com uma pasta aberta (Arquivo ▸ Abrir pasta), os arquivos dentro dela pertencem àquela pasta.
- Para um arquivo fora da pasta aberta, ou sem nenhuma pasta aberta, o
OctoEdit sobe a partir do arquivo procurando
compile_commands.json,compile_flags.txt,.clangd,CMakeLists.txt,Cargo.toml,go.mod,pyrightconfig.json,pyproject.toml,setup.py,tsconfig.json,package.json,pom.xml,build.gradle, um.sln,.gite, por fim, um.editorconfigque declareroot = true. O próprio diretório do arquivo é o recurso de reserva, então um servidor nunca fica sem projeto. - Abrir a pasta depois do arquivo funciona. Servidores que entendem mudanças de pasta de espaço de trabalho são informados da nova pasta; os demais são reiniciados, e seus documentos abertos são reanunciados a eles automaticamente. Nenhum reinício manual é necessário.
Solução de problemas¶
| Sintoma | O que verificar |
|---|---|
O segmento LSP: nunca aparece |
Nenhuma definição de servidor reivindica a extensão deste arquivo. Verifique qual servidor atende qual arquivo, ou acrescente uma definição. |
· server not responding |
O servidor parou de responder. Use Mostrar o log do servidor de linguagem e depois Reiniciar os servidores de linguagem. |
✗ em uma linguagem para a qual você instalou um servidor |
Confirme que o executável está realmente lá: where clangd (Windows) / which clangd (macOS, Linux). Depois, Pesquisar ▸ Navegação no código ▸ Reiniciar os servidores de linguagem, que reexecuta a busca inteira. |
⚠ |
O servidor iniciou e depois ficou falhando. Mostrar o log do servidor de linguagem geralmente nomeia o motivo; conserte-o e use Reiniciar os servidores de linguagem. |
· no compile database em um projeto C/C++ |
Veja acima. Localizar referências e Renomear só verão o arquivo aberto até isso ser corrigido. |
| O autocompletar não devolve nada em um arquivo C++ | Aquele arquivo provavelmente está faltando no compile_commands.json (um cabeçalho não incluído por nenhuma unidade de tradução, ou um arquivo acrescentado depois de o banco de dados ser gerado). Regenere-o. |
| Tudo funciona iniciando por um terminal, mas não pelo Finder | Reporte — a consulta ao PATH do shell de login existe justamente para deixar as duas formas idênticas. Mostrar o log do servidor de linguagem e o log de diagnóstico registram o que foi pesquisado. |
| Um servidor precisa de um arquivo de projeto que você não tem | O typescript-language-server precisa do pacote typescript, o gopls de um go.mod, o rust-analyzer de um Cargo.toml, e o pyright de um pyrightconfig.json/pyproject.toml para respostas de âmbito de projeto. |
Configurações do servidor de linguagem¶
Preferências ▸ Servidor de linguagem lista todas as linguagens para as quais existe uma definição de servidor. Por linguagem você pode:
- Ativar / desativar o servidor (uma linguagem desativada nunca inicia um).
- Definir um caminho de executável explícito (com Procurar…). Essa
substituição vence a busca por
PATH/searchDirsacima — útil quando o servidor não está noPATHou você quer um build específico. - Acrescentar argumentos extras, anexados após os da própria definição — por
exemplo
--log=verbosepara o clangd. A linha é dividida como uma linha de comando, então ponha aspas em torno de um valor que contenha espaços.
O campo de caminho é um caminho, não uma linha de comando
Digitar C:\tools\clangd.exe --log=verbose em Caminho do executável pede ao
OctoEdit que encontre um arquivo cujo nome termine em .exe --log=verbose, o
que não existe — a linguagem então reporta nenhum servidor. Ponha o executável
no campo de caminho e os argumentos dele em Argumentos adicionais. Se acontecer
mesmo assim, o log de diagnóstico diz isso com todas as letras.
As alterações passam a valer quando você pressiona OK / Aplicar: se algum sinalizador de ativação ou caminho realmente mudou, os servidores são reiniciados automaticamente com as novas configurações (uma página intocada nunca perturba os servidores em execução). O botão Examinar de novo / reiniciar os servidores força ainda um desmonte e uma nova descoberta com as configurações atuais — útil depois de instalar um servidor que o editor antes não encontrava —, e ele também zera o orçamento de reinícios por falha.
Abrir a pasta de definições de servidor do usuário cria e abre a pasta descrita em Suas próprias definições de servidor.
Limitações¶
- A coloração de código dentro dos popups de dica não é aplicada (o texto é formatado — negrito, títulos, código monoespaçado — mas sem realce de sintaxe).
- A precisão depende do servidor: para C/C++, sem
compile_commands.jsono clangd recorre a heurísticas e os resultados podem ser incompletos. - O OctoEdit nunca instala nem baixa um servidor. Ele encontra um que você instalou e o inicia; quando não há nenhum, o recurso fica apagado e o segmento de status diz isso.
- Um processo de servidor por linguagem, compartilhado por todos os projetos abertos daquela linguagem. Um segundo projeto é acrescentado como pasta de espaço de trabalho quando o servidor suporta isso; do contrário, ele é atendido sob a raiz do primeiro projeto.
- Kotlin, Swift e Objective-C ganham inteligência de código, mas não coloração de sintaxe — o editor ainda não tem colorizador para eles. Agora as duas coisas são independentes, então o servidor funciona de qualquer forma.
- As definições de servidor são lidas uma vez, na inicialização; editá-las (as suas ou as incluídas) exige reiniciar o editor.