Przejdź do treści

Wtyczka LSP (serwer języka)

Inteligencja kodu napędzana Language Server Protocol — wężyki błędów, nawigacja, dymki, uzupełnianie, pomoc sygnatur, formatowanie, szukanie odwołań, zmiana nazwy i skok do symbolu — dla każdego języka, który ma serwer języka. Edytor rozmawia z serwerem po LSP; wtyczka jest klientem. To, jakie serwery istnieją, jest sterowane danymi (jeden mały JSON na język), więc C++/clangd poniżej to tylko jedna z kilku dołączonych definicji.

Edytor nie dołącza ani nie pobiera serwerów

Serwer języka to osobny program, który instalujesz raz. MTE wykrywa zainstalowany serwer i kieruje go na Twój projekt; nigdy żadnego nie dostarcza. Zobacz Pobieranie serwera języka.

Bieżące funkcje

Funkcja Jak
Diagnostyka Błędy/ostrzeżenia z serwera pojawiają się jako faliste podkreślenia (czerwone = błąd, bursztynowe = ostrzeżenie, niebieskie = informacja, szare = wskazówka), aktualizowane podczas pisania.
Idź do definicji Ustaw kursor na symbolu i naciśnij F12 albo użyj Szukaj ▸ Nawigacja po kodzie ▸ Idź do definicji. Skacze do definicji, otwierając w razie potrzeby inny plik.
Znajdź odwołania Kursor na symbolu → Shift+F12 (albo Szukaj ▸ Nawigacja po kodzie ▸ Znajdź odwołania). Wyniki otwierają się w dolnym panelu Odwołania, pogrupowane po plikach z podglądem linii źródłowej; dwuklik skacze.
Dymek Zatrzymaj wskaźnik nad symbolem; okienko pokazuje jego typ/sygnaturę i dokumentację (renderowaną z Markdownu serwera).
Uzupełnianie Ctrl+Space prosi serwer o uzupełnienia i włącza je do okienka uzupełniania edytora (przed wbudowanymi podpowiedziami słów kluczowych/słów z buforów), filtrując podczas pisania.
Pomoc sygnatur Wpisanie ( wywołania albo , pokazuje podpowiedź z sygnaturą funkcji i podświetlonym aktywnym parametrem; ) ją zamyka.
Formatuj dokument Alt+Shift+F (⌃⌥F na macOS; albo Edycja ▸ Formatuj dokument) formatuje cały dokument przez serwer, jako jeden krok cofania. Styl określa konfiguracja samego serwera (dla clangd — plik .clang-format).
Znajdź odwołania (wyżej) —
Zmień nazwę symbolu Kursor na symbolu → Shift+F6 (albo Edycja ▸ Zmień nazwę symbolu). Podaj nową nazwę; każde użycie zostaje zaktualizowane. Gdy zmiana obejmuje kilka plików, najpierw pada prośba o potwierdzenie — każdy plik jest otwierany, zmieniany i zostawiany zmodyfikowany do przeglądu i zapisu.
Idź do symbolu (w pliku) Ctrl+Shift+O otwiera Paletę poleceń z listą wszystkich symboli bieżącego pliku (funkcje, klasy, metody…); pisz, aby filtrować, Enter skacze. Każdy wiersz pokazuje rodzaj symbolu i jego kontener.
Idź do symbolu w przestrzeni roboczej Ctrl+T przeszukuje symbole w całym projekcie podczas pisania (zapytanie dopasowuje serwer); Enter otwiera plik na symbolu.

Wybieraki skoku do symbolu to tryby symboli Palety poleceń — zobacz Paletę poleceń.

Polecenia są wyszarzone, dopóki serwer nie działa

Przejdź do definicji, Znajdź odwołania, Formatuj dokument i Zmień nazwę symbolu są dostępne tylko wtedy, gdy serwer języka bieżącego pliku jest gotowy — i gdy w powitaniu zgłosił, że obsługuje dane żądanie. Dla pliku bez skonfigurowanego serwera, a także gdy serwer się uruchamia, restartuje albo się poddał, pozycje menu są wyszarzone, zamiast nic nie robić po kliknięciu. Poniższy wskaźnik stanu mówi, który to przypadek. Uruchom ponownie serwery językowe nigdy nie jest wyszarzone: to droga wyjścia z serwera, który się poddał.

Odwołania i zmiana nazwy między plikami wymagają indeksu serwera

Znajdź odwołania i Zmień nazwę sięgają do innych plików dopiero, gdy serwer zaindeksuje projekt. Dla C/C++ oznacza to compile_commands.json (niżej) i indeks działający w tle clangd; bez tego działają tylko na bieżącym pliku.

Zmiana nazwy cofa się na razie per plik

Wieloplikowa zmiana nazwy jest stosowana plik po pliku, więc każdy plik to osobny krok cofania (okno potwierdzenia o tym mówi). Przejrzyj zmodyfikowane karty przed zapisem.

W menu kontekstowym edytora

Kliknij prawym przyciskiem symbol w tekście, a menu pod poleceniami edycji zaproponuje Przejdź do definicji, Znajdź odwołania, Zmień nazwę symbolu i Formatuj dokument. Każda pozycja pojawia się tylko wtedy, gdy to samo polecenie w menu głównym zadziałałoby w tej chwili — serwer języka dla pliku jest gotowy i je obsługuje, a w przypadku zmiany nazwy i formatowania dokument nie jest tylko do odczytu. W zwykłym pliku tekstowym, na marginesie po lewej stronie tekstu albo podczas uruchamiania serwera żadna z nich się nie pojawia.

Pozycje działają na symbolu, który kliknięto prawym przyciskiem, a nie na tym pod karetką; karetka i zaznaczenie zostają na miejscu. Zmiana nazwy proponuje zaznaczenie jako starą nazwę, jeśli kliknięto wewnątrz niego, a w przeciwnym razie słowo pod wskaźnikiem. Formatuj dokument zawsze formatuje cały dokument. Menu otwarte z klawiatury działa w miejscu karetki.

Tam, gdzie platforma pokazuje skróty klawiszowe w menu kontekstowych (Windows), każda pozycja pokazuje swój skrót — ten obowiązujący, łącznie z Twoimi zmianami w mapowaniu skrótów. W macOS menu kontekstowe nie pokazują skrótów.

Jak Twoje zmiany trafiają do serwera

Pisanie nie wysyła komunikatu na każde naciśnięcie klawisza. Zmiany są scalane przez ułamek sekundy i wysyłane jako jedna — i to jako pojedynczy zmieniony zakres, a nie cały plik, o ile serwer zadeklaruje, że to potrafi (większość potrafi). Duży plik kosztuje więc kilkadziesiąt bajtów na serię pisania zamiast kopii samego siebie.

Wszystko, co pyta serwer o tekst — dymki, przejście do definicji, szukanie odwołań, zmiana nazwy, formatowanie, uzupełnianie, pomoc sygnatur — najpierw wysyła oczekującą zmianę, żeby odpowiedź nigdy nie dotyczyła wersji, którą już zdążyłeś zostawić za sobą. Zapis pliku robi to samo.

Uruchomienie serwera także nie blokuje edytora: proces startuje w tle, a segment stanu pokazuje …, dopóki nie skończy uzgadniania. Serwer, który zawiesza się przy starcie, kosztuje Cię tylko ten jeden język.

Górna granica liczby rysowanych problemów

Na jeden dokument rysowanych jest najwyżej 2000 wężyków. Powyżej tej liczby plik i tak jest nieczytelny, a każdy dodatkowy znacznik kosztuje edytor realny czas — więc gdy plik daje ich więcej, pokazywane jest pierwsze 2000, a pasek stanu mówi Pokazano pierwsze 2000 z N problemów w tym pliku, zamiast po cichu zaniżać liczbę. Zwykle to znak, że serwer patrzy na plik niewłaściwie: brakuje bazy kompilacji albo jest to plik generowany, który nie ma się kompilować samodzielnie.

Wskaźnik stanu serwera

Pasek stanu pokazuje zwarty segment LSP: (na lewo od innych segmentów wtyczek), podsumowujący każdy serwer języka istotny dla otwartych plików:

LSP: cpp ✓ · no compile database  python ↻2  rust ✗
Glif Znaczenie
… Start — serwer został uruchomiony i trwa uzgadnianie.
✓ Gotowy — obsługuje żądania.
↻n Restart — serwer zakończył się nieoczekiwanie; zaplanowana jest automatyczna próba restartu nr n.
✗ Brak zainstalowanego serwera dla tego języka. Zainstaluj go (patrz niżej), a potem użyj Uruchom ponownie serwery językowe.
⚠ Poddał się — serwer ciągle się wywalał i automatyczne restarty ustały. Przywraca go tylko restart ręczny.

Za glifem języka może pojawić się krótkie dopowiedzenie — serwer działa, a coś w projekcie nadal ogranicza to, na co potrafi odpowiedzieć. Pokazywane jest tylko jedno naraz, najpoważniejsze najpierw:

Dopowiedzenie Znaczenie
· serwer nie odpowiada Kilka żądań z rzędu pozostało bez odpowiedzi. Serwer żyje, ale utknął: Pokaż dziennik serwera językowego, potem Uruchom ponownie serwery językowe. Dopowiedzenie znika w chwili, gdy serwer na cokolwiek odpowie.
· brak bazy kompilacji Serwer C/C++ działa, ale widzi wyłącznie otwarty plik; patrz Projekty C/C++ potrzebują compile_commands.json.
· brak Cargo.toml, · brak go.mod, · brak tsconfig.json, … Projekt nie ma żadnego z plików, których ten serwer potrzebuje, by rozumieć go jako projekt. Otwarty plik nadal działa; odpowiedzi obejmujące wiele plików będą niepełne, dopóki plik nie powstanie. Nazwa jest tą, na której serwerowi zależy najbardziej — patrz Czego każdy serwer oczekuje od projektu.

Segment pojawia się przy otwarciu pierwszego dokumentu skonfigurowanego języka, śledzi tylko języki, dla których faktycznie masz otwarte dokumenty — zamknięcie ostatniego pliku języka usuwa jego wpis (ponowne otwarcie natychmiast go przywraca) — i znika całkowicie, gdy nie zostaje żaden taki dokument.

Szukaj ▸ Nawigacja po kodzie ▸ Pokaż dziennik serwera językowego pokazuje najnowsze komunikaty każdego działającego serwera. To tam serwer się tłumaczy: brakujący toolchain, nieczytelny plik konfiguracji, projekt, którego nie wczytał. Okno jest zwykłym oknem o zmiennym rozmiarze — każdy język to nagłówek nazywający działający dla niego serwer, tekst można zaznaczać, Kopiuj umieszcza cały dziennik w schowku, a nadany oknu rozmiar jest zapamiętywany.

Gdy serwer się zawiesi

Serwer języka, który kończy się nieoczekiwanie, jest restartowany automatycznie z rosnącym opóźnieniem (1 s, 2 s, 4 s… z limitem 30 s). W tym czasie wskaźnik pokazuje ↻n, a powiadomienie na pasku stanu zgłasza pierwszą awarię. Po udanym restarcie otwarte dokumenty są ponownie zgłaszane serwerowi i diagnostyka wraca sama; nieaktualne wężyki po martwym serwerze są czyszczone od razu. Edycja nigdy nie jest blokowana.

Po 5 nieudanych próbach z rzędu wtyczka się poddaje: wskaźnik pokazuje ✗, powiadomienie kieruje do ustawień, a język pozostaje ciemny, dopóki nie zrestartujesz go ręcznie. Serwer, który działał poprawnie przez co najmniej minutę, przy późniejszej awarii dostaje świeżą pulę prób.

Restart ręczny — jedno z dwojga:

  • Szukaj ▸ Nawigacja po kodzie ▸ Uruchom ponownie serwery językowe (bez domyślnego skrótu; dostępne też z Palety poleceń), albo
  • przycisk Przeskanuj / zrestartuj serwery w Preferencje ▸ Serwer języka.

Oba zatrzymują wszystkie serwery, ponawiają wykrywanie z bieżącymi ustawieniami i resetują budżet awarii — użyj po zainstalowaniu brakującego serwera albo naprawieniu zepsutego.

Aby przed restartem zobaczyć, dlaczego serwer jest niezadowolony, użyj Szukaj ▸ Nawigacja po kodzie ▸ Pokaż dziennik serwera językowego.

Pobieranie serwera języka

Zainstaluj serwer dla swojego języka i upewnij się, że jest w PATH (albo ustaw jawną ścieżkę w ustawieniach). Jeśli nie zostanie znaleziony, funkcja po prostu nic nie robi dla tego języka — wskaźnik stanu pokazuje ✗, a log notuje jednorazową wskazówkę, ale nic Ci nie przeszkadza.

MTE dostarcza definicje serwerów (nie serwery) dla wielu języków, więc większość wymaga tylko instalacji serwera — bez edycji JSON-a. Dołączone definicje obejmują C/C++, Objective-C, Pythona, Rusta, Go, TypeScript, JavaScript, C#, Javę, Kotlina, Swifta, HTML, CSS/SCSS/Less, JSON, YAML i skrypty powłoki.

Język Serwer Skąd wziąć
C/C++ clangd winget install LLVM.LLVM (Windows), komponent „C++ Clang tools" w instalatorze Visual Studio, brew install llvm (macOS) albo pakiet clang-tools-extra Twojej dystrybucji.
Python pyright lub pylsp npm i -g pyright (wymaga Node.js) albo pip install python-lsp-server (wymaga tylko Pythona).
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 lub OmniSharp dotnet tool install -g csharp-ls (pojedyncze narzędzie dotnet, próbowane pierwsze) albo pobrane wydanie OmniSharpa.
Java jdtls (Eclipse JDT Language Server) brew install jdtls (macOS) albo rozpakowane wydanie z katalogiem bin w PATH.

Zweryfikuj w terminalu, np. clangd --version albo where clangd / which clangd. Dla języka bez dołączonej definicji dodaj własną jak w Dodawaniu języka.

Python: pyright albo pylsp

Python ma dwie dołączone definicje, a OctoEdit uruchamia tę, która jest faktycznie zainstalowana:

  1. pyright (pyright-langserver) jest próbowany pierwszy. To pakiet npm, więc wymaga Node.js: npm i -g pyright.
  2. pylsp (python-lsp-server) jest używany, gdy pyrighta nie ma. To pakiet pip i wymaga tylko Pythona: pip install python-lsp-server.

Gdy zainstalowane są oba, wygrywa pyright. W ustawieniach Python ma jeden wiersz (jedną flagę włączenia, jedno nadpisanie ścieżki) i dotyczy on tego serwera, który zostanie użyty — wskazanie jawnej ścieżki do pylsp uruchamia pylsp z jego argumentami, nie z argumentami pyrighta. Pokaż dziennik serwera językowego nazywa serwer, który faktycznie działa.

Kilka serwerów dla jednego języka

To mechanizm ogólny, nie wyjątek dla Pythona: język może mieć dowolnie wiele dołączonych definicji, uporządkowanych polem priority, a startuje pierwsza z nich, której plik wykonywalny znajduje się na Twoim komputerze. C# działa tak samo — najpierw csharp-ls, potem OmniSharp — bo oba przyjmują inne argumenty uruchomienia i tylko jedne z nich mogą być poprawne.

Java: własna przestrzeń robocza serwera

jdtls nie wystartuje bez własnego, zapisywalnego katalogu roboczego (-data). OctoEdit dostarcza go automatycznie, osobno dla każdego projektu, w folderze danych wtyczki:

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

Nigdy nie musisz go tworzyć ani nazywać. Skasowanie folderu jest bezpieczne — jdtls odbuduje go kosztem jednego ponownego indeksowania.

Konfiguracja w systemie Windows

Świeża instalacja Windows zwykle nie ma na PATH żadnego z: clangd, cmake, ninja, node, python. Ta sekcja mówi, skąd wziąć każde z nich i jak to sprawdzić. Zwykle nie musisz sam edytować PATH — OctoEdit przeszukuje też katalogi ekosystemów wymienione niżej.

Czego chcesz Instalacja Gdzie ląduje
clangd (C/C++) winget install LLVM.LLVM C:\Program Files\LLVM\bin\clangd.exe
cmake i ninja Komponent „C++ CMake tools for Windows" w instalatorze Visual Studio …\Microsoft Visual Studio\2022\<edition>\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin i …\CMake\Ninja — nie na PATH, ale osiągalne przez środowisko deweloperskie Visual Studio (patrz niżej). Osobne winget install Kitware.CMake / winget install Ninja-build.Ninja umieszcza je na PATH.
pyright (Python) winget install OpenJS.NodeJS.LTS, potem npm i -g pyright %APPDATA%\npm\pyright-langserver.cmd
pylsp (Python, bez Node) Python ze Sklepu Microsoft lub python.org, potem pip install python-lsp-server %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts\pylsp.exe (Sklep) albo %APPDATA%\Python\Python3*\Scripts\pylsp.exe

Sprawdzenie, co jest widoczne. W zwykłym wierszu poleceń lub PowerShellu:

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

where przeszukuje wyłącznie PATH. Narzędzie, którego nie znajdzie, może mimo to zostać znalezione przez OctoEdit, bo wyszukiwanie obejmuje też powyższe katalogi ekosystemów — w szczególności katalogi skryptów Pythona nigdy nie są na PATH. Jeśli po instalacji serwera język nadal pokazuje ✗, użyj Szukaj ▸ Nawigacja po kodzie ▸ Uruchom ponownie serwery językowe, co powtarza całe wyszukiwanie.

Generowanie bazy kompilacji działa w środowisku deweloperskim Visual Studio. Gdy OctoEdit uruchamia dla Ciebie CMake (patrz niżej), najpierw lokalizuje Visual Studio — przez VSINSTALLDIR, a w przeciwnym razie vswhere.exe — i opakowuje wywołanie w VsDevCmd.bat -arch=x64 tej instalacji. To właśnie udostępnia cl, Windows SDK oraz cmake/ninja z Visual Studio na czas tego jednego polecenia, więc edytor w ogóle nie potrzebuje ich na Twoim PATH. Bez Visual Studio (maszyna tylko z clangiem albo z MinGW) wywołanie jest wykonywane zwyczajnie, w środowisku samego edytora, i dziennik to odnotowuje; wtedy musisz sam mieć osiągalne cmake i ninja oraz kompilator, który CMake rozpozna.

Generowanie na żądanie. Szukaj ▸ Nawigacja po kodzie ▸ Wygeneruj bazę kompilacji… uruchamia to samo generowanie w dowolnym momencie — także gdy baza już istnieje (jest wtedy przekonfigurowana w miejscu) i gdy wcześniej wybrałeś Nie pytaj o ten projekt. Pozycja jest zawsze dostępna — gdy nie może nic wygenerować, mówi na pasku stanu dlaczego (brak dokumentu C/C++, brak folderu projektu, brak CMakeLists.txt w katalogu głównym, brak cmake albo brak generatora, który potrafiłby ją tu wyeksportować), zamiast być wyszarzona z powodu, którego nie widać.

Gdzie zapisywana jest odpowiedź „nie pytaj". Nie pytaj o ten projekt jest pamiętane per katalog główny projektu w %APPDATA%\7-bits\OctoEdit.ini, pod plugins/org.mte.lsp/noCompileDbPrompt/<hash> (ścieżka projektu jest hashowana, bo ścieżka nie jest poprawnym kluczem ustawień). Wygeneruj bazę kompilacji… czyści ten wpis dla danego projektu.

Gdzie OctoEdit szuka serwera

Nie powinieneś musieć niczego konfigurować. Po instalacji serwera wystarczy otworzyć folder i plik źródłowy. Edytor próbuje po kolei:

  1. jawnej ścieżki ustawionej w ustawieniach — rozstrzygającej: jeśli nie wskazuje na plik wykonywalny, język pozostaje ciemny, zamiast po cichu sięgać po coś innego;
  2. Twojego PATH — polecenia serwera i każdego znanego aliasu (clangd-20, clangd-19, …);
  3. lokalizacji instalacji z definicji serwera dla Twojego systemu;
  4. wbudowanej listy katalogów ekosystemów.
Przeszukiwane katalogi ekosystemów
Windows globalny prefiks npm i %APPDATA%\npm, %LOCALAPPDATA%\Microsoft\WinGet\Links, %USERPROFILE%\.cargo\bin, %USERPROFILE%\go\bin i %LOCALAPPDATA%\go\bin, %USERPROFILE%\.dotnet\tools, %ProgramFiles%\LLVM\bin, %ProgramFiles%\nodejs oraz katalogi skryptów Pythona dla użytkownika: %APPDATA%\Python\Python3*\Scripts, %LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.*_*\LocalCache\local-packages\Python3*\Scripts (Python ze Sklepu Microsoft) i %LOCALAPPDATA%\Programs\Python\Python3*\Scripts
macOS /opt/homebrew/bin i /opt/homebrew/opt/llvm/bin (clangd z Homebrew leży w tym drugim — nigdy nie jest linkowany do pierwszego), /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 oraz te same ~/.cargo/bin, ~/go/bin, ~/.local/bin, ~/.npm-global/bin, ~/.dotnet/tools

Wpisy z * to prawdziwe wieloznaczniki: katalog z wersją, który tworzy Python (Python313, 3.13 albo …Python.3.13_qbz5n2kfra8p0 ze Sklepu), jest dopasowywany do tego, co faktycznie jest na dysku, od najnowszego. Tam właśnie pip install python-lsp-server umieszcza pylsp — i dlatego jego instalacja nie wymaga zmiany PATH.

macOS: uruchomienie z Findera a z terminala

Aplikacja uruchomiona z Findera lub Docka nie dziedziczy PATH z profilu Twojej powłoki — macOS daje jej minimalny (/usr/bin:/bin:/usr/sbin:/sbin). Homebrew, Cargo, Go i npm byłyby niewidoczne. Dlatego OctoEdit pyta Twoją powłokę logowania o jej PATH i przeszukuje również jego, a wynikowe środowisko przekazuje uruchamianemu serwerowi — więc serwer zainstalowany dowolnym z tych narzędzi zostaje znaleziony niezależnie od sposobu uruchomienia edytora.

Serwer startuje raz na język i jest zamykany razem z edytorem.

Projekty C/C++ potrzebują compile_commands.json

clangd rozumie Twój kod dokładnie tylko wtedy, gdy zna flagi kompilacji — z bazy kompilacji (compile_commands.json). Bez niej clangd zgaduje, a funkcje międzyplikowe (znajdź odwołania, zmiana nazwy) pozostają ograniczone do otwartego pliku. clangd i tak zostaje uruchomiony.

Projekt C/C++ liczy się jako skonfigurowany, gdy ma dowolne z:

  • compile_commands.json w korzeniu projektu albo w jednym z katalogów budowania skanowanych przez OctoEdit (build/, Build/, out/, out/build/, cmake-build-debug/, cmake-build-release/, .mte-compile-commands/);
  • compile_flags.txt w korzeniu projektu;
  • plik konfiguracji .clangd w korzeniu projektu.

Dwa ostatnie clangd czyta sam, więc nic o nich nie zgłaszamy.

Gdy nie ma żadnego z nich — dla każdego projektu C/C++, niezależnie od systemu budowania — segment stanu pokazuje · brak bazy kompilacji, a komunikat na pasku stanu mówi o tym raz. Nic nie blokuje, żadne okno nie przerywa pisania.

Niech OctoEdit ją wygeneruje (projekty CMake)

Jeśli korzeń projektu ma CMakeLists.txt i dostępny jest CMake, który naprawdę wytworzy bazę, raz na projekt dostajesz propozycję:

  • Wygeneruj — uruchamia CMake w tle, wyłącznie w trybie konfiguracji: nic nie jest kompilowane, a Twoje katalogi budowania pozostają nietknięte. Wynik trafia do <project>/.mte-compile-commands/. Po sukcesie clangd restartuje się z nową bazą; po niepowodzeniu pokazywane są ostatnie linie logu CMake wraz z dokładnym poleceniem, które zostało użyte, żebyś mógł je powtórzyć samodzielnie.
  • Jak zrobić to ręcznie — pokazuje to samo polecenie bez uruchamiania go.
  • Nie pytaj o ten projekt — zapamiętywane osobno dla każdego korzenia.

Zarówno okno „jak zrobić to ręcznie", jak i okno błędu pokazują dokładny wiersz poleceń w polu kodu, które da się zaznaczyć, a pod nim jeden przycisk Kopiuj, którego podpowiedź mówi, co kopiuje: samo polecenie albo polecenie razem z końcówką logu CMake, gdy jakiś jest. Okno błędu ma zmienny rozmiar i zapamiętuje ten, który mu nadasz — każde z tych okien pamięta własny rozmiar, więc powiększenie dziennika serwera nie sprawia, że dwuwierszowe okno z instrukcją otwiera się równie duże.

Nie jesteś ograniczony do tej jednej propozycji: Szukaj ▸ Nawigacja po kodzie ▸ Wygeneruj bazę kompilacji… uruchamia to samo generowanie, kiedy tylko chcesz — po dodaniu plików, po zmianie opcji budowania albo po wcześniejszym wybraniu Nie pytaj o ten projekt (co zostaje wyczyszczone). Istniejąca baza jest przekonfigurowywana w miejscu. Pozycja jest zawsze dostępna; gdy nie może nic wygenerować, mówi na pasku stanu dlaczego.

Najpierw Twoje zestawy ustawień. Jeśli projekt ma CMakePresets.json (albo CMakeUserPresets.json), OctoEdit konfiguruje jednym z Twoich presetów, zamiast wymyślać własny wiersz poleceń — cmake --preset <name> -B <project>/.mte-compile-commands -DCMAKE_EXPORT_COMPILE_COMMANDS=ON. Dzięki temu generator, zestaw narzędzi i blok environment presetu (QT6_DIR, ścieżka do SDK) są tymi, na których projekt już polega, a CMake sam je stosuje. Presety ukryte, wykluczone przez condition na Twoim systemie albo konfigurujące generatorem, który nie potrafi eksportować, są pomijane; preferowana jest nazwa zawierająca debug. Twój własny katalog budowania nigdy nie jest ruszany — edytor zawsze przekierowuje wynik przez -B.

Na Windows CMake jest uruchamiany w środowisku deweloperskim Visual Studio. Edytor uruchomiony z Eksploratora lub menu Start nie ma cl w PATH, a CMake po cichu zadowoli się dowolnym innym kompilatorem, który znajdzie — w tym clang.exe dostarczanym wewnątrz instalacji Visual Studio, co natychmiast kończy się błędem na ustawieniach specyficznych dla MSVC. Dlatego OctoEdit lokalizuje Visual Studio przez vswhere i opakowuje wywołanie w VsDevCmd.bat -arch=x64. Jeśli Visual Studio nie ma (maszyna wyłącznie z MinGW lub clangiem), wywołanie idzie wprost, a log to odnotowuje.

Poprzednia nieudana próba jest sprzątana przed ponowieniem: jej CMakeCache.txt przypiąłby kompilator, który zawiódł. Katalog zawierający już działający compile_commands.json jest rekonfigurowany w miejscu, nigdy kasowany.

Dlaczego propozycja czasem się nie pojawia

CMAKE_EXPORT_COMPILE_COMMANDS honorują tylko generatory Ninja i Makefile; generator Visual Studio go ignoruje i nie zapisuje żadnej bazy. Dlatego na Windows, dla projektu bez użytecznego presetu, propozycja pojawia się tylko wtedy, gdy w PATH jest ninja. Gdy jedyne pasujące presety projektu są tymi od Visual Studio i nie ma też Ninji, OctoEdit mówi, który preset stanął na przeszkodzie, zamiast proponować uruchomienie czegoś, co nie mogłoby zadziałać.

Generowanie samodzielne (CMake)

CMAKE_EXPORT_COMPILE_COMMANDS honorują tylko generatory Ninja i Makefile — generator Visual Studio go ignoruje (nie tworzy compile_commands.json nawet z ustawioną flagą). Generuj więc bazę Ninją, do dedykowanego katalogu, osobnego od tego, w którym zwykle budujesz: CMake odmawia rekonfiguracji istniejącego katalogu budowania innym generatorem, więc projekt budowany zwykle Visual Studio potrzebuje własnego katalogu Ninja.

To krok wyłącznie konfiguracyjny (pełny build nie jest potrzebny). Z korzenia projektu:

cmake -S . -B .mte-compile-commands -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
  • .mte-compile-commands/ to jeden ze skanowanych katalogów, więc wynikowy compile_commands.json zostaje znaleziony automatycznie. Zadziała też każdy inny skanowany katalog (build/, out/, cmake-build-* albo korzeń projektu) — trzymaj go tylko osobno od katalogu skonfigurowanego innym generatorem.
  • Uruchom to w środowisku, w którym projekt naprawdę się konfiguruje: właściwy kompilator w PATH (np. x64 Native Tools Command Prompt na Windows) i zmienne, których projekt wymaga (jak QT6_DIR dla projektu Qt). Jeśli cmake nie znajdzie kompilatora lub SDK, baza wyjdzie pusta albo bez ścieżek include i clangd nie zaindeksuje dobrze.
  • Potem otwórz folder ponownie. Log nie powinien już mówić „no compile_commands.json"; daj clangd chwilę na zbudowanie indeksu w tle, zanim odwołania/zmiana nazwy obejmą pliki.

Inne systemy budowania: Bear (bear -- make), compiledb, Meson, Bazel i inne też potrafią wytworzyć compile_commands.json, który wtyczka znajdzie.

Który serwer obsługuje który plik

Decyduje nazwa pliku. Każda definicja serwera wymienia rozszerzenia, które obsługuje, i startuje pierwsza definicja zgłaszająca rozszerzenie pliku. Dopasowanie ignoruje wielkość liter i liczy się tylko ostatnia kropka — Deploy.Prod.SH to skrypt powłoki.

Jest to celowo niezależne od kolorowania składni. Wyłączenie kolorowania albo otwarcie pliku większego niż limit rozmiaru kolorowania nie kosztuje Cię już także serwera językowego.

Identyfikator kolorowania nadal jest zapasem

Jeśli żadna definicja nie zgłasza rozszerzenia, OctoEdit sięga po identyfikator języka nadany przez silnik kolorowania. Dzięki temu ręcznie napisana definicja działa, gdy nazywa język, ale nie wymienia rozszerzeń.

Nazwa, którą serwer dostaje, to druga, osobna sprawa: LSP ma własne słownictwo identyfikatorów języków i kilka z nich nie pokrywa się z tymi OctoEdit. Plik .sh jest zgłaszany jako shellscript, .scss jako scss, .jsx jako javascriptreact, .mm jako objective-cpp. Serwery, które zachowują się różnie zależnie od języka — serwer CSS, serwer TypeScriptu — potrzebują poprawnej nazwy.

Rozszerzenie Obsługuje Zgłaszane jako
.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

.h zgłasza definicja C/C++, a nie ta dla Objective-C — obie uruchamiają clangd, który sam rozstrzyga, co zawiera nagłówek.

Czego każdy serwer oczekuje od projektu

Kilka serwerów działa poprawnie dopiero wtedy, gdy w katalogu głównym projektu leży określony plik. Gdy go brakuje, wskaźnik stanu mówi o tym wprost, zamiast udawać, że wszystko jest w porządku:

Język Oczekuje Bez tego
Rust Cargo.toml rust-analyzer w ogóle nie wczyta skrzynki.
Go go.mod gopls nie rozwiąże modułu.
TypeScript tsconfig.json (albo package.json) odpowiedzi obejmujące cały projekt są niedostępne.
JavaScript jsconfig.json (albo package.json) jak wyżej.
Python (pyright) pyproject.toml / pyrightconfig.json / setup.py pyright nadal działa; po prostu używa domyślnych korzeni importu i domyślnej surowości.
Java pom.xml / build.gradle jdtls nie zbuduje ścieżki klas.
C/C++ compile_commands.json patrz sekcja powyżej.

Dodawanie języka

Serwery opisują pliki JSON ładowane przez wtyczkę przy starcie z <editor>/lsp-servers/*.json oraz z Twojego folderu. Każdy wpis mapuje język na jego polecenie plus wskazówki wykrywania:

{
    "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 to własny identyfikator języka w OctoEdit — klucz, wokół którego grupują się strona ustawień, segment stanu i połączenie. command/aliases to nazwy plików wykonywalnych próbowane w PATH.
  • extensions to podstawowe odwzorowanie pliku na język (patrz wyżej). Z kropką.
  • args to jeden element tablicy na każdy argument. ["--background-index", "--log=verbose"] przekazuje dwa argumenty; ["--background-index --log=verbose"] przekazuje jeden argument, który zawiera spację — a taki odrzuca każdy serwer i natychmiast kończy pracę, więc wygląda to na pętlę awarii, a nie na literówkę. OctoEdit ostrzega o tym kształcie w dzienniku diagnostycznym przy wczytywaniu Twojego pliku.
  • languageId (opcjonalny) to identyfikator wysyłany serwerowi w didOpen; domyślnie równy language. Użyj go, gdy nazwa ze specyfikacji LSP różni się od naszej (bash → shellscript, objc → objective-c).
  • languageIds (opcjonalny) nadpisuje languageId per rozszerzenie, dla jednego serwera obsługującego kilka języków ze specyfikacji.
  • projectMarkers (opcjonalny) to nazwy plików, których serwer oczekuje w katalogu głównym projektu. Gdy nie ma żadnego z nich, segment stanu pokazuje brak <first marker>; nigdy nie zatrzymuje to serwera.
  • searchDirs to lista lokalizacji instalacji dla Windows; searchDirsMac i searchDirsLinux to jej odpowiedniki dla pozostałych systemów. Wszystkie trzy rozwijają ${VAR}, a listy POSIX-owe rozwijają też wiodące ~. Wpis, którego zmienne nie są ustawione, jest pomijany, a nie zamieniany w bezsensowną ścieżkę.
  • args może użyć dwóch symboli zastępczych: ${dataDir} — zapisywalnego folderu danych wtyczki — oraz ${rootHash} — krótkiego, stałego identyfikatora bieżącego projektu. Tak jdtls dostaje -data <dir>. Symbol, którego nie da się rozwinąć, zostaje w argumencie dosłownie, zamiast rozwinąć się w nic.
  • compileCommandsArg (opcjonalny) jest dołączany z ${dir} zastąpionym znalezionym katalogiem bazy — tak clangd zostaje skierowany na compile_commands.json.
  • priority (opcjonalny, domyślnie 0) porządkuje kilka definicji tego samego języka: najniższa liczba jest próbowana pierwsza, a startuje pierwsza definicja, której plik wykonywalny zostanie znaleziony. Tak Python dostaje pyrighta (priority: 0) z pylsp (priority: 10) jako rozwiązaniem zapasowym.

Twoje własne definicje serwerów

Dołączone definicje leżą w katalogu instalacyjnym, którego nie edytujesz (Program Files w Windows, podpisany pakiet aplikacji w macOS). Swoje umieść obok nich: Preferencje ▸ Serwer językowy ▸ Otwórz folder własnych definicji serwerów tworzy i otwiera

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

Każdy plik *.json w tym folderze jest wczytywany po zestawie dołączonym, przy czym:

  • plik, którego language i command pokrywają się z definicją dołączoną, zastępuje ją — tak zmienisz argumenty clangd albo dodasz katalog wyszukiwania;
  • wszystko inne jest dodawane — drugi serwer dla języka, który dostarczamy, albo język, dla którego OctoEdit nie dostarcza nic.

Plik, który nie jest poprawnym JSON-em albo nie ma language czy command, jest pomijany i odnotowany w dzienniku diagnostycznym, zamiast po cichu kosztować Cię język.

Definicje są czytane raz, przy starcie: po ich edycji uruchom ponownie edytor (przycisk Wyszukaj ponownie / uruchom ponownie serwery ponawia wyszukiwanie, a nie wczytanie).

Minimalna definicja użytkownika: <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"]
}

Który folder dostaje serwer

Serwer języka musi wiedzieć, gdzie jest projekt: rust-analyzer bez tego nie wczyta skrzynki, gopls potrzebuje korzenia modułu, pyright czyta stamtąd pyrightconfig.json, a clangd szuka tam swojej bazy.

  • Przy otwartym folderze (Plik ▸ Otwórz folder) pliki w nim należą do tego folderu.
  • Dla pliku poza otwartym folderem albo bez otwartego folderu OctoEdit idzie w górę od pliku, szukając 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, pliku .sln, .git, a na końcu .editorconfig z root = true. Awaryjnie służy katalog samego pliku, więc serwer nigdy nie zostaje bez projektu.
  • Otwarcie folderu po pliku działa. Serwery rozumiejące zmiany folderów roboczych dostają o nich powiadomienie; pozostałe są restartowane, a otwarte dokumenty zgłaszane im automatycznie. Ręczny restart nie jest potrzebny.

Rozwiązywanie problemów

Objaw Co sprawdzić
Segment LSP: w ogóle się nie pojawia Żadna definicja serwera nie zgłasza rozszerzenia tego pliku. Sprawdź który serwer obsługuje który plik albo dodaj definicję.
· serwer nie odpowiada Serwer przestał odpowiadać. Pokaż dziennik serwera językowego, potem Uruchom ponownie serwery językowe.
✗ dla języka, dla którego zainstalowałeś serwer Potwierdź, że plik wykonywalny naprawdę tam jest: where clangd (Windows) / which clangd (macOS, Linux). Potem Szukaj ▸ Nawigacja po kodzie ▸ Uruchom ponownie serwery językowe, co powtarza całe wyszukiwanie.
⚠ Serwer wystartował, a potem ciągle się wywalał. Pokaż dziennik serwera językowego zwykle nazywa przyczynę; napraw ją i zrestartuj serwery.
· brak bazy kompilacji w projekcie C/C++ Patrz wyżej. Znajdź odwołania i Zmień nazwę do tego czasu widzą tylko otwarty plik.
Uzupełnianie nic nie zwraca w jednym pliku C++ Tego pliku najpewniej nie ma w compile_commands.json (nagłówek, którego nie włącza żadna jednostka translacji, albo plik dodany po wygenerowaniu bazy). Wygeneruj ją ponownie.
Z terminala działa wszystko, z Findera nie Zgłoś to — odczyt PATH z powłoki logowania ma zrównywać oba przypadki. Pokaż dziennik serwera językowego i log Diagnostyki notują, co było przeszukiwane.
Serwer wymaga pliku projektu, którego nie masz typescript-language-server potrzebuje pakietu typescript, gopls go.mod, rust-analyzer Cargo.toml, a pyright pyrightconfig.json/pyproject.toml do odpowiedzi obejmujących cały projekt.

Ustawienia serwera języka

Preferencje ▸ Serwer językowy wymienia każdy język z istniejącą definicją serwera. Per język możesz:

  • Włączyć / wyłączyć serwer (wyłączony język nigdy go nie uruchamia).
  • Ustawić jawną ścieżkę pliku wykonywalnego (z Przeglądaj…). To nadpisanie wygrywa z powyższym wyszukiwaniem PATH/searchDirs — przydatne, gdy serwera nie ma w PATH albo chcesz konkretny build.
  • Dodać Dodatkowe argumenty, doklejane po własnych argumentach definicji — na przykład --log=verbose dla clangd. Wiersz jest dzielony jak wiersz poleceń, więc wartość ze spacjami ujmij w cudzysłów.

Pole ścieżki to ścieżka, nie wiersz poleceń

Wpisanie C:\tools\clangd.exe --log=verbose w Ścieżkę pliku wykonywalnego każe OctoEdit szukać pliku, którego nazwa kończy się na .exe --log=verbose — taki nie istnieje, więc język zgłasza brak serwera. Plik wykonywalny wpisz w pole ścieżki, a jego argumenty w Dodatkowe argumenty. Jeśli mimo to tak się stanie, dziennik diagnostyczny mówi to wprost.

Zmiany działają po OK / Zastosuj: jeśli którakolwiek flaga włączenia lub ścieżka faktycznie się zmieniła, serwery restartują się z nowymi ustawieniami automatycznie (niedotknięta strona nigdy nie rusza działających serwerów). Przycisk Przeskanuj / zrestartuj serwery dodatkowo wymusza zatrzymanie i ponowne wykrycie z bieżącymi ustawieniami — przydatne po instalacji serwera, którego edytor wcześniej nie znajdował; resetuje też budżet restartów po awarii.

Otwórz folder własnych definicji serwerów tworzy i otwiera folder opisany w Twoje własne definicje serwerów.

Ograniczenia

  • Kolorowanie kodu w dymkach nie jest stosowane (tekst jest formatowany — pogrubienia, nagłówki, kod o stałej szerokości — ale bez kolorowania składni).
  • Dokładność zależy od serwera: dla C/C++ bez compile_commands.json clangd wraca do heurystyk i wyniki mogą być niepełne.
  • OctoEdit nigdy nie instaluje ani nie pobiera serwera. Znajduje ten, który zainstalowałeś, i go uruchamia; gdy żadnego nie ma, funkcja pozostaje ciemna, a segment stanu to pokazuje.
  • Jeden proces serwera na język, wspólny dla wszystkich otwartych projektów tego języka. Drugi projekt jest dodawany jako folder roboczy, jeśli serwer to obsługuje; w przeciwnym razie jest obsługiwany w korzeniu pierwszego projektu.
  • Kotlin, Swift i Objective-C mają inteligencję kodu, ale nie mają kolorowania składni — edytor nie ma dla nich jeszcze kolorowania. Obie rzeczy są teraz niezależne, więc serwer działa mimo to.
  • Definicje serwerów są czytane raz, przy starcie; ich edycja (Twoich lub dołączonych) wymaga ponownego uruchomienia edytora.