Vai al contenuto

Plugin LSP (language server)

Intelligenza del codice mossa dal Language Server Protocol: ghirigori di errore, navigazione, suggerimenti al passaggio del mouse, completamento, aiuto sulla firma, formattazione, trova riferimenti, rinomina e vai al simbolo, per qualsiasi linguaggio che abbia un language server. L'editor parla con il server tramite LSP; il plugin è il client. Quali server esistono è guidato dai dati (un piccolo JSON per linguaggio), quindi C++/clangd qui sotto è solo una di diverse definizioni incluse.

L'editor non include né scarica server

Un language server è un programma separato che installi una volta. MTE rileva un server installato e lo punta al tuo progetto; non ne distribuisce mai uno. Vedi Procurarsi un language server.

Funzionalità attuali

Funzionalità Come
Diagnostiche Errori/avvisi del server compaiono come sottolineature ondulate (rosso = errore, ambra = avviso, blu = informazione, grigio = suggerimento), aggiornate mentre digiti.
Vai alla definizione Metti il cursore su un simbolo e premi F12, oppure usa Cerca ▸ Navigazione nel codice ▸ Vai alla definizione. Salta alla definizione, aprendo un altro file se serve.
Trova i riferimenti Cursore su un simbolo → Shift+F12 (o Cerca ▸ Navigazione nel codice ▸ Trova i riferimenti). I risultati si aprono in un pannello inferiore Riferimenti, raggruppati per file con un'anteprima della riga sorgente; doppio clic per saltare.
Suggerimento al passaggio del mouse Lascia il puntatore su un simbolo; una finestra a comparsa mostra il tipo/la firma e la documentazione (resi dal Markdown del server).
Completamento Ctrl+Space richiede completamenti al server e li fonde nella finestra di completamento dell'editor (davanti ai suggerimenti integrati da parole chiave e buffer), filtrati mentre digiti.
Aiuto sulla firma Digitare la ( o una , di una chiamata mostra un suggerimento con la firma della funzione e il parametro attivo evidenziato; ) lo chiude.
Formatta il documento Alt+Shift+F (⌃⌥F su macOS; oppure Modifica ▸ Formatta il documento) riformatta l'intero documento tramite il server, in un unico passo di annullamento. Lo stile è retto dalla configurazione del server stesso (per clangd, un file .clang-format).
Trova i riferimenti (elencato sopra) —
Rinomina il simbolo Cursore su un simbolo → Shift+F6 (o Modifica ▸ Rinomina il simbolo). Inserisci un nome nuovo; ogni uso viene aggiornato. Quando la rinomina abbraccia più file ti viene chiesta prima una conferma: ogni file viene aperto, modificato e lasciato modificato perché tu lo esamini e lo salvi.
Vai al simbolo (nel file) Ctrl+Shift+O apre la tavolozza dei comandi con l'elenco di ogni simbolo del file corrente (funzioni, classi, metodi…); digita per filtrare, Invio salta. Ogni riga mostra il tipo del simbolo e il suo contenitore.
Vai al simbolo nell'area di lavoro Ctrl+T cerca simboli in tutto il progetto mentre digiti (è il server a fare la corrispondenza); Invio apre il file al simbolo.

I selettori di vai-al-simbolo sono le modalità simbolo della tavolozza dei comandi: vedi Tavolozza dei comandi.

I comandi restano in grigio finché un server non è in esecuzione

Vai alla definizione, Trova i riferimenti, Formatta il documento e Rinomina il simbolo sono attivi solo quando un language server per il linguaggio del file corrente è Pronto, e quando quel server ha dichiarato nel suo saluto iniziale di supportare la richiesta. Su un file senza server configurato, o mentre uno sta partendo, riavviandosi o ha rinunciato, le voci di menu appaiono in grigio invece di non fare nulla quando le premi. L'indicatore di stato qui sotto ti dice quale dei casi sia. Riavvia i language server non va mai in grigio: è la via d'uscita da un server che ha rinunciato.

Riferimenti tra file e rinomina richiedono l'indice del server

Trova riferimenti e Rinomina raggiungono altri file solo dopo che il server ha indicizzato il progetto. Per C/C++ questo significa un compile_commands.json (vedi sotto) e l'indice in secondo piano di clangd; senza, operano solo sul file corrente.

Per ora la rinomina si annulla per file

Una rinomina su più file viene applicata un file per volta, quindi ogni file è un proprio passo di annullamento (la finestra di conferma lo dice). Esamina le schede modificate prima di salvare.

Nel menu contestuale dell'editor

Fai clic con il tasto destro su un simbolo nel testo e il menu offre, sotto i comandi di modifica, Vai alla definizione, Trova i riferimenti, Rinomina il simbolo e Formatta il documento. Ciascuno compare solo quando lo stesso comando del menu principale funzionerebbe in quel momento: un language server per il file è pronto e lo supporta e, per Rinomina e Formatta, il documento non è in sola lettura. In un file di testo semplice, nel margine a sinistra del testo o mentre il server si sta avviando, non ne compare nessuno.

Le voci agiscono sul simbolo su cui hai fatto clic con il tasto destro, non su quello sotto il cursore; il cursore e la selezione restano dove erano. Rinomina propone la selezione come vecchio nome quando hai fatto clic al suo interno, altrimenti la parola sotto il puntatore. Formatta il documento formatta sempre l'intero documento. Un menu aperto dalla tastiera agisce sulla posizione del cursore.

Dove la piattaforma mostra le scorciatoie da tastiera nei menu contestuali (Windows), ogni voce mostra la propria scorciatoia: quella in vigore, comprese le tue modifiche nella Mappatura delle scorciatoie. Su macOS i menu contestuali non mostrano scorciatoie.

Come le tue modifiche raggiungono il server

Digitare non invia un messaggio per ogni tasto. Le modifiche vengono raggruppate per una frazione di secondo e poi inviate come un'unica modifica, e come un unico intervallo modificato invece dell'intero file, ogni volta che il server dichiara di poterne accettare uno (la maggior parte può). Un file grande costa quindi qualche decina di byte per raffica di digitazione invece di una copia di se stesso.

Tutto ciò che chiede al server qualcosa sul testo —suggerimento al passaggio del mouse, vai alla definizione, trova riferimenti, rinomina, formatta, completamento, aiuto sulla firma— invia prima la modifica in sospeso, così una risposta non si riferisce mai a una versione che hai già superato. Salvare un file fa lo stesso.

Avviare un server non blocca nemmeno l'editor: il processo viene lanciato in secondo piano e il segmento di stato mostra … finché non ha completato il saluto iniziale. Un binario di server che si blocca all'avvio non ti costa nulla oltre quel linguaggio.

Un tetto a quanti problemi vengono disegnati

Vengono disegnati al massimo 2000 ghirigori per documento. Oltre quella soglia il file è comunque illeggibile, e ogni indicatore in più costa tempo reale all'editor; quindi, quando un file ne produce di più, vengono mostrati i primi 2000 e la barra di stato dice Mostrati i primi 2000 di N problemi in questo file, invece di lasciare che il conteggio appaia in silenzio inferiore a quello che è. Di solito è segno che il server sta guardando male il file: un database di compilazione mancante, o un file generato che non è pensato per compilare da solo.

L'indicatore di stato del server

La barra di stato mostra un segmento compatto LSP: (a sinistra degli altri segmenti dei plugin) che riassume ogni language server rilevante per i tuoi file aperti:

LSP: cpp ✓ · no compile database  python ↻2  rust ✗
Glifo Significato
… In avvio — il server è stato lanciato e sta facendo il saluto iniziale.
✓ Pronto — sta servendo le richieste.
↻n In riavvio — il server si è fermato inaspettatamente; è programmato il tentativo automatico di riavvio numero n.
✗ Nessun server installato per questo linguaggio. Installane uno (vedi sotto), poi usa Riavvia i language server.
⚠ Ha rinunciato — il server continuava a fallire e i riavvii automatici si sono fermati. Solo un riavvio manuale lo rianima.

Un linguaggio può portare un breve qualificatore dopo il glifo: il server è in esecuzione, e qualcosa nel tuo progetto limita ancora ciò a cui può rispondere. Ne viene mostrato uno alla volta, il più grave per primo:

Qualificatore Significato
· server not responding Diverse richieste di fila sono rimaste senza risposta. Il server è vivo ma bloccato; usa Mostra il log del language server, poi Riavvia i language server. Il qualificatore sparisce nel momento in cui il server risponde a qualcosa.
· no compile database Il server C/C++ è in esecuzione, ma vede solo il file che hai aperto: vedi I progetti C/C++ richiedono compile_commands.json.
· no Cargo.toml, · no go.mod, · no tsconfig.json, … Il progetto non ha nessuno dei file di cui questo server ha bisogno per intenderlo come progetto. Funziona comunque sul file aperto; le risposte tra file resteranno incomplete finché quel file non esiste. Il nome esatto è quello che il server desidera di più: vedi Che cosa serve a ciascun server dal tuo progetto.

Il segmento compare quando si apre il primo documento con un linguaggio configurato, segue solo i linguaggi di cui hai davvero documenti aperti —chiudere l'ultimo file di un linguaggio ne rimuove la voce (riaprirne uno la riporta all'istante)— e si nasconde del tutto quando non resta alcun documento del genere.

Cerca ▸ Navigazione nel codice ▸ Mostra il log del language server mostra l'output più recente di ogni server in esecuzione. È lì che un server si spiega: una catena di strumenti mancante, un file di configurazione illeggibile, un progetto che ha rifiutato di caricare. La finestra è normale e ridimensionabile: ogni linguaggio è un titolo che nomina il server in esecuzione per esso, il testo si può selezionare, Copia mette l'intero log negli appunti, e la dimensione che dai alla finestra viene ricordata.

Se un server si arresta

Un language server che termina inaspettatamente viene riavviato automaticamente con un ritardo crescente (1 s, 2 s, 4 s… con un tetto di 30 s). Mentre questo accade l'indicatore mostra ↻n e una notifica nella barra di stato segnala il primo arresto. Dopo un riavvio riuscito i tuoi documenti aperti vengono riannunciati al server e le diagnostiche tornano da sole; i ghirigori obsoleti del server morto vengono cancellati subito. La modifica non viene mai bloccata.

Dopo 5 tentativi falliti di fila il plugin rinuncia: l'indicatore mostra ✗, una notifica ti rimanda alle impostazioni, e il linguaggio resta spento finché non lo riavvii a mano. Un server che è girato bene per almeno un minuto riceve una nuova serie di tentativi quando si arresta più tardi.

Riavvio manuale — uno dei due:

  • Cerca ▸ Navigazione nel codice ▸ Riavvia i language server (senza scorciatoia predefinita; disponibile anche nella tavolozza dei comandi), oppure
  • il pulsante Nuova scansione / riavvia i server in Preferenze ▸ Server di linguaggio.

Per vedere perché un server è scontento prima di riavviarlo, usa Cerca ▸ Navigazione nel codice ▸ Mostra il log del language server.

Entrambi smontano ogni server, rieseguono il rilevamento con le impostazioni attuali e azzerano il budget di fallimenti: usali dopo aver installato un server mancante o dopo averne riparato uno rotto.

Procurarsi un language server

Installa il server del tuo linguaggio e assicurati che sia nel tuo PATH (oppure imposta un percorso esplicito nelle impostazioni). Se non ne viene trovato nessuno, la funzionalità semplicemente non fa nulla per quel linguaggio: l'indicatore di stato mostra ✗ e il log registra un suggerimento una volta sola, ma nulla ti interrompe.

MTE include definizioni di server (non i server) per molti linguaggi, quindi alla maggior parte basta che il server sia installato, senza modificare alcun JSON. Le definizioni incluse coprono C/C++, Objective-C, Python, Rust, Go, TypeScript, JavaScript, C#, Java, Kotlin, Swift, HTML, CSS/SCSS/Less, JSON, YAML e script di shell.

Linguaggio Server Dove procurarselo
C/C++ clangd winget install LLVM.LLVM (Windows), il componente «C++ Clang tools» nell'installer di Visual Studio, brew install llvm (macOS), oppure il pacchetto clang-tools-extra della tua distribuzione.
Python pyright o pylsp npm i -g pyright (richiede Node.js), oppure pip install python-lsp-server (richiede solo 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 o OmniSharp dotnet tool install -g csharp-ls (un unico strumento dotnet, provato per primo), oppure scarica una versione di OmniSharp.
Java jdtls (Eclipse JDT Language Server) brew install jdtls (macOS), oppure scompatta una versione e metti il suo bin nel tuo PATH.

Verifica in un terminale, ad esempio clangd --version oppure where clangd / which clangd. Per un linguaggio di cui MTE non include una definizione, aggiungine una come descritto in Aggiungere un linguaggio.

Python: pyright o pylsp

Python ha due definizioni incluse, e OctoEdit esegue quella davvero installata:

  1. pyright (pyright-langserver) viene provato per primo. È un pacchetto npm, quindi richiede Node.js: npm i -g pyright.
  2. pylsp (python-lsp-server) viene usato quando pyright non si trova. È un pacchetto pip e richiede solo Python: pip install python-lsp-server.

Se sono installati entrambi, vince pyright. C'è un'unica riga di impostazioni per Python (un indicatore di attivazione, una sostituzione di percorso) e vale per qualunque server venga usato: impostare un percorso esplicito a un eseguibile pylsp esegue pylsp con i suoi argomenti di avvio, non quelli di pyright. Mostra il log del language server nomina il server davvero in esecuzione.

Più server per un linguaggio

Questo è un meccanismo generale, non un caso speciale di Python: un linguaggio può avere un numero qualsiasi di definizioni incluse, ordinate da un campo priority, e la prima il cui eseguibile si trova sulla tua macchina è quella che parte. C# funziona allo stesso modo —csharp-ls prima, OmniSharp poi— perché i due ricevono argomenti di avvio diversi e solo uno può essere quello giusto.

Java: l'area di lavoro del server stesso

jdtls si rifiuta di partire senza una directory di area di lavoro scrivibile propria (-data). OctoEdit ne fornisce una automaticamente, per progetto, sotto la sua cartella dati del plugin:

<user data>/plugins/org.mte.lsp/jdtls-workspaces/<project id>/

Non devi mai crearla né darle un nome. Eliminare la cartella è sicuro: jdtls la ricostruisce, al costo di una reindicizzazione.

Configurazione su Windows

Una macchina Windows appena installata di solito non ha nessuno di clangd, cmake, ninja, node o python nel suo PATH. Questa sezione dice da dove viene ciascuno e come controllare. Normalmente non devi modificare tu il PATH: OctoEdit cerca anche nelle directory di ecosistema elencate sotto.

Ciò che vuoi Installa Dove finisce
clangd (C/C++) winget install LLVM.LLVM C:\Program Files\LLVM\bin\clangd.exe
cmake e ninja Il componente «C++ CMake tools for Windows» nell'Installer di Visual Studio …\Microsoft Visual Studio\2022\<edition>\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin e …\CMake\Ninja — non nel tuo PATH, ma raggiungibili attraverso l'ambiente di sviluppo di Visual Studio (vedi sotto). Un winget install Kitware.CMake / winget install Ninja-build.Ninja autonomo li mette invece nel PATH.
pyright (Python) winget install OpenJS.NodeJS.LTS, poi npm i -g pyright %APPDATA%\npm\pyright-langserver.cmd
pylsp (Python, senza Node) Python dal Microsoft Store o da python.org, poi pip install python-lsp-server %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts\pylsp.exe (Store) oppure %APPDATA%\Python\Python3*\Scripts\pylsp.exe

Controllare che cosa è visibile. In un normale Prompt dei comandi o PowerShell:

where clangd
where cmake
where ninja
where pyright-langserver
where pylsp

where cerca solo nel tuo PATH. Uno strumento che non trova può comunque essere trovato da OctoEdit, perché la ricerca copre anche le directory di ecosistema qui sopra: le directory degli script di Python, in particolare, non sono mai nel PATH. Se un linguaggio resta a ✗ dopo aver installato il suo server, usa Cerca ▸ Navigazione nel codice ▸ Riavvia i language server, che riesegue l'intera ricerca.

La generazione del database di compilazione gira dentro l'ambiente di sviluppo di Visual Studio. Quando OctoEdit esegue CMake al posto tuo (sotto), prima individua Visual Studio —tramite VSINSTALLDIR, altrimenti con vswhere.exe— e avvolge la chiamata nel VsDevCmd.bat -arch=x64 di quell'installazione. È questo a mettere cl, l'SDK di Windows e il cmake/ninja di Visual Studio nel percorso per quel singolo comando, così l'editor non ha affatto bisogno che siano nel tuo PATH. Senza Visual Studio (una macchina con solo clang o con MinGW) la chiamata viene fatta semplicemente, nell'ambiente dell'editor stesso, e il log lo dice; ti servono allora cmake e ninja raggiungibili per conto tuo, e un compilatore che CMake possa identificare.

Rigenerare su richiesta. Cerca ▸ Navigazione nel codice ▸ Genera il database di compilazione… esegue la stessa generazione in qualsiasi momento, anche quando un database esiste già (viene riconfigurato sul posto) e quando in passato avevi risposto Non chiedere per questo progetto. La voce è sempre disponibile: quando non può generare, dice perché nella barra di stato (nessun documento C/C++, nessuna cartella di progetto, nessun CMakeLists.txt nella radice del progetto, nessun cmake, o nessun generatore qui in grado di esportarne uno) invece di restare in grigio per un motivo che non puoi vedere.

Dove viene salvata la risposta di «non chiedere». Non chiedere per questo progetto viene salvata per radice di progetto in %APPDATA%\7-bits\OctoEdit.ini, sotto plugins/org.mte.lsp/noCompileDbPrompt/<hash> (il percorso del progetto viene ridotto a hash perché un percorso non è una chiave di impostazioni valida). Eseguire Genera il database di compilazione… la cancella per quel progetto.

Dove OctoEdit cerca un server

Non dovresti dover configurare nulla. Dopo aver installato un server, basta aprire una cartella e un file sorgente. In ordine, l'editor prova:

  1. un percorso esplicito che hai impostato nelle impostazioni — che comanda: se non si risolve, il linguaggio resta spento invece di ricadere in silenzio su qualcos'altro;
  2. il tuo PATH, per il comando del server e per ogni alias noto (clangd-20, clangd-19, …);
  3. le posizioni di installazione della definizione del server per il tuo sistema operativo;
  4. un elenco integrato di directory di ecosistema.
Directory di ecosistema esaminate
Windows il prefisso globale di 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 le directory degli script di Python per utente: %APPDATA%\Python\Python3*\Scripts, %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts (Python dal Microsoft Store) e %LOCALAPPDATA%\Programs\Python\Python3*\Scripts
macOS /opt/homebrew/bin e /opt/homebrew/opt/llvm/bin (il clangd di Homebrew vive nel secondo: non viene mai collegato nel primo), /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 gli stessi ~/.cargo/bin, ~/go/bin, ~/.local/bin, ~/.npm-global/bin, ~/.dotnet/tools

Le voci con * sono veri caratteri jolly: la directory di versione che Python crea (Python313, 3.13, oppure il …Python.3.13_qbz5n2kfra8p0 dello Store) viene confrontata con ciò che c'è davvero su disco, dalla più recente. È lì che pip install python-lsp-server mette pylsp, ed è per questo che installarlo non richiede modifiche al PATH.

macOS: avviare dal Finder contro avviare da un terminale

Un'applicazione avviata dal Finder o dal Dock non eredita il PATH dal profilo della tua shell: macOS gliene dà uno minimo (/usr/bin:/bin:/usr/sbin:/sbin). Homebrew, Cargo, Go e npm sarebbero tutti invisibili. Per questo OctoEdit chiede alla tua shell di accesso qual è il suo PATH e cerca anche lì, e passa l'ambiente risultante al server che avvia: così un server installato da uno qualsiasi di quegli strumenti si trova comunque tu avvii l'editor.

Il server viene avviato una volta per linguaggio e spento con l'editor.

I progetti C/C++ richiedono compile_commands.json

clangd comprende il tuo codice con precisione solo quando conosce le opzioni di compilazione, da un database di compilazione (compile_commands.json). Senza, clangd ricade su supposizioni e le funzionalità tra file (trova riferimenti, rinomina) restano limitate al file aperto. clangd viene avviato comunque.

Un progetto C/C++ conta come configurato quando ha uno qualsiasi di questi:

  • un compile_commands.json nella radice del progetto o in una delle directory di build che OctoEdit esamina (build/, Build/, out/, out/build/, cmake-build-debug/, cmake-build-release/, .mte-compile-commands/);
  • un compile_flags.txt nella radice del progetto;
  • un file di configurazione .clangd nella radice del progetto.

clangd legge gli ultimi due per conto suo, quindi su di essi non viene segnalato nulla.

Quando non ce n'è nessuno —per ogni progetto C/C++, qualunque sia il suo sistema di build— il segmento di stato mostra · no compile database e un messaggio nella barra di stato lo dice una volta. Nulla si blocca; nessuna finestra interrompe la tua digitazione.

Lasciare che OctoEdit lo generi (progetti CMake)

Se la radice del progetto ha un CMakeLists.txt e un CMake che produrrebbe davvero un database, questo ti viene proposto una volta per progetto:

  • Genera — esegue CMake in secondo piano, solo la configurazione: non viene compilato nulla e le tue directory di build restano intatte. Il risultato va in <project>/.mte-compile-commands/. Se riesce, clangd viene riavviato sul nuovo database; se fallisce, vengono mostrate le ultime righe del log di CMake, insieme al comando esatto che è stato tentato, così puoi ripeterlo tu.
  • Come farlo manualmente — mostra quello stesso comando senza eseguirlo.
  • Non chiedere per questo progetto — ricordato per radice di progetto.

Sia la finestra di «come farlo a mano» sia quella di errore mostrano la riga di comando esatta in una casella di codice selezionabile, sopra un unico pulsante Copia il cui suggerimento dice che cosa porta con sé: il comando da solo, oppure il comando insieme al tratto finale del log di CMake quando c'è. La finestra di errore è ridimensionabile e ricorda la dimensione che le dai: ognuna di queste finestre ricorda la propria dimensione, così ingrandire il log del server non fa aprire altrettanto grande una finestra di istruzioni di due righe.

Non sei limitato a quell'unica proposta: Cerca ▸ Navigazione nel codice ▸ Genera il database di compilazione… avvia la stessa generazione quando vuoi —dopo aver aggiunto file, dopo aver cambiato opzioni di build, o dopo aver risposto Non chiedere per questo progetto (che così viene cancellata)—. Un database esistente viene riconfigurato sul posto. La voce è sempre disponibile; e quando non può generare, dice perché nella barra di stato.

Le tue preimpostazioni vengono prima. Se il progetto ha un CMakePresets.json (o un CMakeUserPresets.json), OctoEdit configura con una delle tue preimpostazioni invece di inventarsi una riga di comando: cmake --preset <name> -B <project>/.mte-compile-commands -DCMAKE_EXPORT_COMPILE_COMMANDS=ON. Così il generatore, la catena di strumenti e il blocco environment della preimpostazione (un QT6_DIR, un percorso di SDK) sono quelli su cui il progetto già fa affidamento, ed è CMake ad applicarli. Le preimpostazioni nascoste, quelle che una condition esclude sul tuo sistema operativo, o quelle che configurano con un generatore incapace di esportare vengono saltate; si preferisce un nome che contenga debug. La tua directory di build non viene mai toccata: l'editor reindirizza sempre l'output con -B.

Su Windows, CMake viene eseguito dentro un ambiente di sviluppo di Visual Studio. Un editor avviato da Esplora risorse o dal menu Start non ha cl nel suo PATH, e CMake si accontenterebbe allora in silenzio di qualunque altro compilatore trovi, incluso il clang.exe che sta dentro un'installazione di Visual Studio, che fallisce subito su impostazioni specifiche di MSVC. Per questo OctoEdit individua Visual Studio con vswhere e avvolge la chiamata in VsDevCmd.bat -arch=x64. Se non c'è alcun Visual Studio installato (una macchina MinGW o solo con clang) la chiamata viene fatta semplicemente e il log lo dice.

Un tentativo fallito precedente viene ripulito prima di un nuovo tentativo: il suo CMakeCache.txt fisserebbe altrimenti il compilatore che ha fallito. Una directory che contiene già un compile_commands.json funzionante viene riconfigurata sul posto, mai eliminata.

Perché a volte la proposta non compare

CMAKE_EXPORT_COMPILE_COMMANDS è rispettato solo dai generatori Ninja e Makefile; il generatore di Visual Studio lo ignora e non scrive alcun database. Quindi su Windows, per un progetto senza alcuna preimpostazione utilizzabile, la proposta compare solo quando ninja è nel tuo PATH. Quando le uniche preimpostazioni applicabili di un progetto sono di Visual Studio e non c'è nemmeno Ninja, OctoEdit dice quale preimpostazione si è messa di traverso invece di proporsi di eseguire qualcosa che non potrebbe funzionare.

Generarlo tu stesso (CMake)

CMAKE_EXPORT_COMPILE_COMMANDS è rispettato solo dai generatori Ninja e Makefile: il generatore di Visual Studio lo ignora (non produce alcun compile_commands.json nemmeno con l'opzione attiva). Quindi genera il database con Ninja, in una directory dedicata, separata da quella in cui compili di solito: CMake si rifiuta di riconfigurare una directory di build esistente con un generatore diverso, quindi un progetto che di solito compili con Visual Studio ha bisogno di una propria directory Ninja.

Questo è un passo di sola configurazione (non serve una compilazione completa). Dalla radice del progetto:

cmake -S . -B .mte-compile-commands -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
  • .mte-compile-commands/ è una delle directory che MTE esamina, quindi il compile_commands.json risultante viene trovato automaticamente. Va bene anche qualsiasi altra directory esaminata (build/, out/, cmake-build-*, o la radice del progetto): tienila solo separata da una directory configurata con un altro generatore.
  • Eseguilo da un ambiente in cui il progetto si configuri davvero: il compilatore giusto nel PATH (ad esempio un x64 Native Tools Command Prompt su Windows) e le variabili di cui il tuo progetto ha bisogno (come QT6_DIR per un progetto Qt). Se cmake non trova il tuo compilatore o SDK, il database finisce vuoto o senza percorsi di inclusione e clangd non indicizzerà bene.
  • Riapri la cartella dopo. Il log non dovrebbe più dire «no compile_commands.json»; concedi a clangd un momento per costruire il suo indice in secondo piano prima che riferimenti e rinomina abbraccino più file.

Altri sistemi di build: Bear (bear -- make), compiledb, Meson, Bazel e altri possono produrre un compile_commands.json che il plugin troverà.

Quale server serve quale file

Decide il nome del file. Ogni definizione di server elenca le estensioni che serve, e la prima definizione che reclama l'estensione di un file è quella che parte. La corrispondenza ignora maiuscole e minuscole, e conta solo l'ultimo punto: Deploy.Prod.SH è uno script di shell.

Questo è deliberatamente indipendente dalla colorazione della sintassi. Spegnere la colorazione, o aprire un file più grande del limite di dimensione della colorazione, non ti costa più anche il language server.

L'id del colorizzatore resta una riserva

Se nessuna definizione reclama l'estensione, OctoEdit ricade sull'id di linguaggio assegnato dal motore di colorazione. Questo mantiene funzionante una definizione scritta a mano che nomina un linguaggio ma non elenca estensioni.

Il nome che viene comunicato al server è una seconda cosa, separata: LSP ha un proprio vocabolario di id di linguaggio, e diversi non coincidono con quelli di OctoEdit. Un file .sh viene annunciato come shellscript, uno .scss come scss, uno .jsx come javascriptreact, uno .mm come objective-cpp. I server che si comportano diversamente a seconda del linguaggio —il server CSS, quello TypeScript— hanno bisogno che questo sia corretto.

Estensione Servita da Annunciata come
.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

Il .h è reclamato dalla definizione C/C++ e non da quella Objective-C: entrambe eseguono clangd, che decide da sé che cosa contiene un'intestazione.

Che cosa serve a ciascun server dal tuo progetto

Diversi server funzionano bene solo quando un file preciso si trova nella radice del progetto. Quando manca, l'indicatore di stato lo dice invece di far finta che vada tutto bene:

Linguaggio Vuole Senza di esso
Rust Cargo.toml rust-analyzer non caricherà affatto il crate.
Go go.mod gopls non riesce a risolvere il modulo.
TypeScript tsconfig.json (o package.json) le risposte di ambito progetto non sono disponibili.
JavaScript jsconfig.json (o package.json) come sopra.
Python (pyright) pyproject.toml / pyrightconfig.json / setup.py pyright funziona comunque; usa solo valori predefiniti per le radici di importazione e il rigore.
Java pom.xml / build.gradle jdtls non riesce a costruire un classpath.
C/C++ compile_commands.json vedi la sezione qui sopra.

Aggiungere un linguaggio

I server sono descritti da file JSON che il plugin carica all'avvio da <editor>/lsp-servers/*.json, più la tua cartella. Ogni voce associa un linguaggio al suo comando, più suggerimenti per il rilevamento:

{
    "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 è l'id che OctoEdit dà al linguaggio: la chiave per cui sono raggruppati la pagina delle impostazioni, il segmento di stato e la connessione. command/aliases sono i nomi di eseguibile provati nel PATH.
  • extensions è la mappatura principale da file a linguaggio (vedi sopra). Includi il punto.
  • args prevede un elemento dell'array per argomento. ["--background-index", "--log=verbose"] passa due argomenti; ["--background-index --log=verbose"] passa un argomento che per caso contiene uno spazio, cosa che ogni server rifiuta; e poiché esso termina subito, il risultato sembra un ciclo di arresti invece di un refuso. OctoEdit avvisa di quella forma nel log di diagnostica quando carica il tuo file.
  • languageId (facoltativo) è l'id inviato al server in didOpen; per impostazione predefinita assume il valore di language. Usalo quando il nome della specifica LSP differisce dal nostro (bash → shellscript, objc → objective-c).
  • languageIds (facoltativo) sostituisce languageId per estensione, per un solo server che serve più linguaggi della specifica.
  • projectMarkers (facoltativo) sono i nomi di file che il server vuole nella radice del progetto. Quando nessuno di essi è presente il segmento di stato dice nessun <first marker>; non ferma mai il server.
  • searchDirs è l'elenco delle posizioni di installazione di Windows; searchDirsMac e searchDirsLinux sono le controparti per piattaforma. Tutte e tre espandono ${VAR}, e gli elenchi POSIX espandono anche una ~ iniziale. Una voce le cui variabili non sono impostate viene saltata invece di trasformarsi in un percorso senza senso.
  • args può usare due segnaposto: ${dataDir}, la cartella dati scrivibile del plugin, e ${rootHash}, un id breve e stabile del progetto corrente. È così che jdtls riceve -data <dir>. Un segnaposto che non si può risolvere viene lasciato alla lettera nell'argomento invece di essere espanso a nulla.
  • compileCommandsArg (facoltativo) viene aggiunto in coda, con ${dir} sostituito dalla directory del database individuata: è così che clangd viene puntato a compile_commands.json.
  • priority (facoltativo, 0 per impostazione predefinita) ordina più definizioni dello stesso linguaggio: il numero più basso viene provato per primo, e la prima definizione il cui eseguibile si trova è quella che parte. È così che Python ottiene pyright (priority: 0) con pylsp (priority: 10) come riserva.

Le tue definizioni di server

Le definizioni incluse vivono dentro la directory di installazione, che non è tua da modificare (Program Files su Windows, un bundle di applicazione firmato su macOS). Metti le tue accanto a esse: Preferenze ▸ Language server ▸ Apri la cartella delle definizioni server dell'utente crea e apre

<user data>/plugins/org.mte.lsp/lsp-servers/

Ogni *.json al suo interno viene caricato dopo l'insieme incluso, e:

  • un file il cui language e command corrispondono a una definizione inclusa la sostituisce: è così che cambi gli argomenti di clangd o aggiungi una directory di ricerca;
  • qualsiasi altra cosa viene aggiunta: un secondo server per un linguaggio che distribuiamo, o un linguaggio per cui OctoEdit non distribuisce nulla.

Un file che non è JSON valido, o a cui manca language o command, viene saltato e segnalato nel log di diagnostica invece di costarti un linguaggio in silenzio.

Le definizioni vengono lette una volta sola, all'avvio: riavvia l'editor dopo averle modificate (il pulsante Riesamina / riavvia i server riesegue la ricerca, non il caricamento).

Una definizione utente minima: <user data>/…/lsp-servers/zig.json
{
    "language":   "zig",
    "command":    "zls",
    "extensions": [".zig", ".zon"],
    "projectMarkers": ["build.zig"],
    "searchDirs":      ["${LOCALAPPDATA}/zls"],
    "searchDirsMac":   ["/opt/homebrew/bin", "~/.local/bin"],
    "searchDirsLinux": ["~/.local/bin"]
}

Quale cartella viene data al server

Un language server ha bisogno di sapere dov'è il progetto: rust-analyzer non carica un crate senza, gopls ha bisogno della radice del modulo, pyright vi legge pyrightconfig.json e clangd vi cerca il suo database.

  • Con una cartella aperta (File ▸ Apri cartella), i file al suo interno appartengono a quella cartella.
  • Per un file fuori dalla cartella aperta, o senza alcuna cartella aperta, OctoEdit risale dal file cercando 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, un .sln, .git e, da ultimo, un .editorconfig che dichiari root = true. La directory del file stesso è la riserva, così un server non resta mai senza progetto.
  • Aprire la cartella dopo il file funziona. Ai server che comprendono i cambi di cartella dell'area di lavoro viene comunicata la nuova cartella; gli altri vengono riavviati, e i tuoi documenti aperti vengono riannunciati loro automaticamente. Non serve alcun riavvio manuale.

Risoluzione dei problemi

Sintomo Che cosa controllare
Il segmento LSP: non compare mai Nessuna definizione di server reclama l'estensione di questo file. Controlla quale server serve quale file, oppure aggiungi una definizione.
· server not responding Il server ha smesso di rispondere. Usa Mostra il log del language server, poi Riavvia i language server.
✗ per un linguaggio di cui hai installato un server Verifica che l'eseguibile ci sia davvero: where clangd (Windows) / which clangd (macOS, Linux). Poi Cerca ▸ Navigazione nel codice ▸ Riavvia i language server, che riesegue l'intera ricerca.
⚠ Il server è partito e poi ha continuato a fallire. Mostra il log del language server di solito nomina il motivo; risolvilo, poi usa Riavvia i language server.
· no compile database su un progetto C/C++ Vedi sopra. Trova riferimenti e Rinomina vedranno solo il file aperto finché non viene risolto.
Il completamento non restituisce nulla su un file C++ Quel file probabilmente manca in compile_commands.json (un'intestazione non inclusa da alcuna unità di traduzione, o un file aggiunto dopo la generazione del database). Rigeneralo.
Tutto funziona avviando da un terminale ma non dal Finder Segnalalo: la consultazione del PATH della shell di accesso esiste proprio per rendere identiche le due vie. Mostra il log del language server e il log di diagnostica registrano che cosa è stato cercato.
Un server ha bisogno di un file di progetto che non hai typescript-language-server ha bisogno del pacchetto typescript, gopls di un go.mod, rust-analyzer di un Cargo.toml, e pyright di un pyrightconfig.json/pyproject.toml per le risposte di ambito progetto.

Impostazioni del language server

Preferenze ▸ Language server elenca ogni linguaggio per cui esiste una definizione di server. Per linguaggio puoi:

  • Attivare / disattivare il server (un linguaggio disattivato non ne avvia mai uno).
  • Impostare un percorso esplicito dell'eseguibile (con Sfoglia…). Questa sostituzione vince sulla ricerca per PATH/searchDirs di cui sopra: utile quando il server non è nel PATH o vuoi una build precisa.
  • Aggiungere argomenti extra, accodati dopo quelli della definizione stessa — ad esempio --log=verbose per clangd. La riga viene divisa come si divide una riga di comando, quindi metti le virgolette attorno a un valore che contiene spazi.

Il campo del percorso è un percorso, non una riga di comando

Digitare C:\tools\clangd.exe --log=verbose in Percorso dell'eseguibile chiede a OctoEdit di trovare un file il cui nome finisce in .exe --log=verbose, che non esiste: il linguaggio riporta allora nessun server. Metti l'eseguibile nel campo del percorso e i suoi argomenti in Argomenti aggiuntivi. Se succede comunque, il log di diagnostica lo dice a chiare lettere.

Le modifiche hanno effetto quando premi OK / Applica: se qualche indicatore di attivazione o percorso è davvero cambiato, i server vengono riavviati automaticamente con le nuove impostazioni (una pagina non toccata non disturba mai i server in esecuzione). Il pulsante Nuova scansione / riavvia i server forza inoltre uno smontaggio e un nuovo rilevamento con le impostazioni attuali —utile dopo aver installato un server che l'editor prima non trovava— e azzera anche il budget di riavvii per arresto.

Apri la cartella delle definizioni server dell'utente crea e apre la cartella descritta in Le tue definizioni di server.

Limitazioni

  • Dentro le finestre a comparsa dei suggerimenti non viene applicata la colorazione del codice (il testo è formattato —grassetto, titoli, codice a spaziatura fissa— ma senza evidenziazione della sintassi).
  • La precisione dipende dal server: per C/C++, senza compile_commands.json clangd ricade su euristiche e i risultati possono essere incompleti.
  • OctoEdit non installa né scarica mai un server. Trova quello che hai installato e lo avvia; quando non ce n'è nessuno, la funzionalità resta spenta e il segmento di stato lo dice.
  • Un processo di server per linguaggio, condiviso da ogni progetto aperto di quel linguaggio. Un secondo progetto viene aggiunto come cartella di area di lavoro quando il server lo supporta; altrimenti viene servito sotto la radice del primo progetto.
  • Kotlin, Swift e Objective-C ottengono intelligenza del codice ma non colorazione della sintassi: l'editor non ha ancora un colorizzatore per loro. Ora le due cose sono indipendenti, quindi il server funziona comunque.
  • Le definizioni di server vengono lette una volta all'avvio; modificarle (le tue o quelle incluse) richiede il riavvio dell'editor.