Додаток клієнта LSP

За допомогою додатка клієнта LSP можна отримати доступ до багатьох можливостей, зокрема автоматичного доповнення коду, навігації кодом та пошуку довідкової інформації на основі протоколу сервера мов (Language Server Protocol).

Після позначення пункту додатка клієнта LSP на сторінці додатків, у діалоговому вікні налаштовування Kate з’явиться нова сторінка із назвою «Клієнт LSP».

Структура меню

Нижче, у пояснення щодо пунктів меню, наведено відповідні команди LSP (якщо такі існують). У документації з цих команд можна знайти додаткові відомості та пояснення, які можуть залежати від мови програмування, яку використано. Термін «поточний символ» використано на позначення символу, який відповідає поточній позиції курсора і визначається на основі мови програмування та з використанням відповідної реалізації сервера обробки.

Клієнт LSPПерейти до визначення

[textDocument/definition] Перейти до визначення поточного символу.

Клієнт LSPПерейти до оголошення

[textDocument/declaration] Перейти до оголошення поточного символу.

Клієнт LSPПерейти до визначення типу

[textDocument/typeDefinition] Перейти до визначення типу поточного символу.

Клієнт LSPЗнайти посилання

[textDocument/references] Знайти посилання на поточний символ.

Клієнт LSPЗнайти реалізації

[textDocument/implementation] Знайти реалізації поточного символу.

Клієнт LSPПідсвітити

[textDocument/documentHighlight] Підсвітити посилання на поточний символ у поточному документі.

Клієнт LSPНаведення

[textDocument/hover] Показати при наведенні дані щодо поточного символу.

Клієнт LSPФорматувати

[textDocument/formatting] [textDocument/rangeFormatting] Форматувати поточний документ або поточний позначений фрагмент документа.

Клієнт LSPПерейменувати

[textDocument/rename] Перейменувати поточний символ.

Клієнт LSPШвидке виправлення

[textDocument/codeAction, workspace/executeCommand] Обчислює і застосовує швидке виправлення для діагностики у поточній позиції (або рядку).

Клієнт LSPПоказувати документацію щодо доповнення позначеного

Показати документацію щодо позначеного елемента у списку автоматичного доповнення.

Клієнт LSPУвімкнути довідку щодо підписів із автодоповненням

Крім того, показувати довідку щодо підписів у списку автозавершення.

Клієнт LSPВключати оголошення до посилань

Надіслати запит щодо включення оголошення поточного символу при запиті щодо посилань.

Клієнт LSPДодавати дужки при доповненні функцій

Автоматично додати пару дужок після автоматично доповненої назви функції.

Клієнт LSPПоказувати відомості при наведенні

Показати дані, які програма показує при наведенні вказівника миші. Незалежно від значення цього параметра, запит щодо цих даних можна завжди ініціювати вручну.

Клієнт LSPФорматувати при введенні

[document/onTypeFormatting] Форматувати частини документа, коли користувач вводитиме певні контрольні символи. Прикладом може бути застосування відступів рядків при введенні символу розриву рядка або іншого форматування, яке визначено на сервері LSP. Зауважте, що скрипти встановлення відступів текстового редактора можуть намагатися виконати те саме завдання (залежно від режиму роботу), тому не радимо одночасно використовувати обидва ці засоби форматування.

Клієнт LSPНарощувальна синхронізація документів

Надсилати для обробки сервером окремі частини документа під час редагування, а не цілий документ (якщо підтримку такого режиму обробки передбачено на сервері).

Клієнт LSPПідсвітити місце переходу

Надати тимчасовий візуальний сигнал після виконання переходу до місця (визначення, оголошення тощо).

Клієнт LSPПоказувати діагностичні сповіщення

[textDocument/publishDiagnostics] Обробити і показати діагностичні сповіщення, які було надіслано сервером.

Клієнт LSPПоказувати підсвічування діагностики

Додати підсвічування фрагментів тексту для діапазонів, які визначено діагностикою.

Клієнт LSPПоказувати позначки діагностики

Додати позначки у документі для рядків, які визначено діагностикою.

Клієнт LSPПеремкнутися на вкладку діагностики

Перемкнутися на вкладку діагностики на панелі інструментів додатків.

Клієнт LSPЗакрити усі вкладки, які не є діагностичними

Закрити усі вкладки (наприклад, вкладки посилань) на панелі інструментів додатків, які не пов'язано із діагностикою.

Клієнт LSPПерезапустити сервер LSP

Перезапустити сервер LSP документа.

Клієнт LSPПерезапустити усі сервери LSP

Зупинити роботу усіх серверів LSP, які згодом, якщо потрібно, буде запущено або перезапущено.

Підтримка переходу до символів

Клієнт LSP може допомогти вам у переході до будь-якого символу у вашому проєкті або поточному файлі. Щоб перейти до будь-якого символу у файлі, скористайтеся кнопками панелі «Схема символів клієнта LSP» у правій частині вікна Kate. На цій панелі ви побачите списки усіх символів, які було знайдено сервером у поточному документі.

Налаштовування схеми символів клієнта LSP

Типово, символи буде упорядковано за їхнім розташуванням у документі, але ви можете наказати програмі упорядкувати їх за абеткою. Для цього клацніть правою кнопкою на панелі і позначте у контекстному меню пункт «Упорядкувати за абеткою».

Типово, на панелі символи буде показано у форматі ієрархічної структури. Втім, ви можете змінити формат на звичайний для списків за допомогою контекстного меню.

Підтримка переходу до загальних символів

Щоб перейти до будь-якого символу у вашому проєкті, ви можете відкрити вікно переходу до символу за допомогою комбінації клавіш Ctrl+Alt+P. Одразу після відкриття вікно буде порожнім, але щойно ви щось введете з клавіатури, програма почне показувати у вікні відповідні символи. Якість відповідності, а також можливості з фільтрування залежать від використаного вами сервера. Наприклад, для clangd передбачено можливість нечіткого фільтрування, але у деяких інших серверів такої можливості не передбачено.

Інші можливості

Передбачено підтримку перемикання заголовка початкового коду Clangd. Щоб перемкнути заголовок початкового коду у проєкті C або C++, скористайтеся пунктом «Перемкнути файл заголовка/коду» у контекстному меню або натисніть клавішу F12.

Ви можете швидко перейти до символу, навівши на нього вказівник миші і натиснувши комбінації Ctrl + ліва кнопка миші.

Налаштування

За допомогою сторінки налаштовування додатка ви можете визначити типові значення для описаних вище пунктів меню. Втім, на цій сторінці є один додатковий пункт, за допомогою якого можна вказати файл налаштувань сервера. Цей файл є файлом JSON, яким можна наказати серверу LSP запускатися (і потім вести обмін даними за допомогою stdin/stdout). Для зручності, до типового пакунка включено типовий файл налаштувань, який можна вивчати на сторінці налаштування додатка. Щоб полегшити розуміння наведених нижче пояснень, ось витяг з налаштувань:

{
    "servers": {
        "bibtex": {
            "use": "latex",
            "highlightingModeRegex": "^BibTeX$"
        },
        "c": {
            "command": ["clangd", "-log=error", "--background-index"],
            "commandDebug": ["clangd", "-log=verbose", "--background-index"],
            "url": "https://clang.llvm.org/extra/clangd/",
            "highlightingModeRegex": "^(C|ANSI C89|Objective-C)$"
        },
        "cpp": {
            "use": "c",
            "highlightingModeRegex": "^(C\\+\\+|ISO C\\+\\+|Objective-C\\+\\+)$"
        },
        "d": {
            "command": ["dls", "--stdio"],
            "url": "https://github.com/d-language-server/dls",
            "highlightingModeRegex": "^D$"
        },
        "fortran": {
            "command": ["fortls"],
            "rootIndicationFileNames": [".fortls"],
            "url": "https://github.com/hansec/fortran-language-server",
            "highlightingModeRegex": "^Fortran.*$"
        },
        "javascript": {
            "command": ["typescript-language-server", "--stdio"],
            "rootIndicationFileNames": ["package.json", "package-lock.json"],
            "url": "https://github.com/theia-ide/typescript-language-server",
            "highlightingModeRegex": "^JavaScript.*$",
            "documentLanguageId": false
        },
        "latex": {
            "command": ["texlab"],
            "url": "https://texlab.netlify.com/",
            "highlightingModeRegex": "^LaTeX$"
        },
        "go": {
            "command": ["go-langserver"],
            "commandDebug": ["go-langserver", "-trace"],
            "url": "https://github.com/sourcegraph/go-langserver",
            "highlightingModeRegex": "^Go$"
        },
        "python": {
            "command": ["python3", "-m", "pyls", "--check-parent-process"],
            "url": "https://github.com/palantir/python-language-server",
            "highlightingModeRegex": "^Python$"
        },
        "rust": {
            "command": ["rls"],
            "path": ["%{ENV:HOME}/.cargo/bin", "%{ENV:USERPROFILE}/.cargo/bin"],
            "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
            "url": "https://github.com/rust-lang/rls",
            "highlightingModeRegex": "^Rust$"
        },
        "ocaml": {
            "command": ["ocamlmerlin-lsp"],
            "url": "https://github.com/ocaml/merlin",
            "highlightingModeRegex": "^Objective Caml.*$"
        }
    }
}

Зауважте, що кожен запис команди («command») може масивом або рядком (який буде поділено на записи масиву). Крім того, буде взято до уваги запис верхнього рівня «global» (поряд із «server»)(докладніший опис наведено нижче). Пошук вказаного виконуваного файла відбуватиметься у звичний спосіб, наприклад, з використанням PATH. Якщо виконуваний файл встановлено у якомусь нетиповому місці, шлях до цього місця може бути згодом розгорнуто. Крім того, можна скористатися у записі місця (символічним) посиланням або скриптом-обгорткою, який зберігається у звичайному PATH. Як проілюстровано вище, можна також вказати «path», місце, в якому буде виконано пошук після стандартних місць.

В усіх записах «command», «root» та «path» буде виконано розгортання змінних.

Інструкцією «highlightingModeRegex» можна скористатися для прив'язування режиму підсвічування, який використовує Kate, до ідентифікатора мови сервера. Якщо не буде надано формального виразу, буде використано сам ідентифікатор мови. Якщо для запису «documentLanguageId» встановлено значення false, при відкритті документа серверу не буде передано ідентифікатора мови. Це може дати кращі результати для деяких серверів, які є точнішими у визначенні типу документа, ніж засоби на основі режиму Kate.

З наведеного вище прикладу можна зрозуміти суть. Крім того, кожен об'єкт запису сервера може мати запис "initializationOptions", який містить дані, які передаються серверу як частина методу «initialize». Якщо такий запис буде знайдено, параметр «settings» буде передано серверу за допомогою сповіщення «workspace/didChangeConfiguration».

Застосовуються різні етапи перевизначення та об'єднання.

  • Налаштування користувача (завантажені з файла) мають пріоритет над типовими (вбудованими) налаштуваннями.

  • Запис «lspclient» у налаштуваннях проєкту .kateproject має пріоритет над усіма попередніми записами.

  • Отриманий у результаті обробки запис «global» використовується як доповнення (не перевизначення) будь-якого із записів сервера.

Для кожної комбінації (root, servertype) використовується один екземпляр сервера. Якщо значення "root" вказано як абсолютний шлях, його буде використано без обробки. Якщо ж це не так, значення вважатиметься вказаним відносно каталогу «projectBase» (як його визначено у додатку проєктів), якщо такий існує, або відносно каталогу документа, якщо цього каталогу не існує. Якщо значення не вказано, і "rootIndicationFileNames" є масивом назв файлів, буде використано батьківський каталог поточного документа, який містить такий файл. Останнім резервним варіантом для "root" є домашній каталог користувача. Для будь-якого документа отриманий у результаті описаної обробки "root" визначає, чи потрібен окремий екземпляр сервера. Якщо такий екземпляр потрібен, значення "root" буде передано як rootUri/rootPath.

Загалом, рекомендуємо не визначати "root", оскільки він не є важливим для роботи сервера (хоча, ви можете визначити його у вашому конкретному випадку). Якщо екземплярів сервера буде небагато, вони працюватимуть ефективніше і матимуть, очевидно, «ширше» поле зору, ніж у випадку використання багатьох окремих екземплярів сервера.

Як вже згадували вище, у деяких записах буде використано розгортання змінних. Належне використання цієї можливості у поєднанні із підходом із використанням «скрипту-обгортки» забезпечує належні можливості налаштовування для широкого спектра застосувань. Наприклад, розглянемо сценарій із мовою розробки python. Нехай маємо декілька проєктів (наприклад, у сховищах git), у кожного з яких є власна конфігурація віртуального середовища. Якщо скористатися типовими налаштуваннями, сервер мови python не отримає даних щодо віртуального середовища. Втім, цю проблему можна розв'язати за допомогою викладеного нижче підходу. По-перше, до «Параметрів сервера користувача» додатка LSPClient слід ввести вказаний нижче фрагмент коду:

{
        "servers":
        {
                "python":
                {
                        "command": ["pylsp_in_env"], ["%{Project:NativePath}"],
                        "root": "."
                }
        }
}

Запис «root» вище є відносним щодо каталогу проєкту. Його призначено для запуску окремого сервера мов для кожного з проєктів. У цьому випадку такий поділ є необхідним, оскільки кожен проєкт має своє віртуальне середовище.

pylsp_in_env — невеличкий «скрипт-обгортка», який має бути збережено до одного з каталогів зі змінної PATH із таким вмістом (вміст слід скоригувати за вашими потребами):

#!/bin/bash
cd $1
# запустити сервер (python-lsp-server) у віртуальному середовищі
# (тобто із заданими змінними віртуального середовища)
# тому командуємо source для віртуального середовища
source XYZ
# сервер і аргументи можуть бути різними
exec myserver

Налаштування сервера LSP

У кожного окремо взятого сервера LSP є власний спосіб налаштовування. У ньому можуть використовуватися специфічні засоби для мови або інструменти, наприклад tox.ini (для python), .clang-format для форматування у стилі C++. Такі налаштування може бути потім використано іншими (не пов'язаними із LSP) інструментами (зокрема tox або clang-format). Крім того, деякі сервери LSP завантажують налаштування з нетипових файлів (наприклад, .ccls). Далі, нетипові налаштування сервера можна передавати за допомогою LSP (протоколу), див. згадані раніше записи «initializationOptions» і «settings» у налаштуваннях сервера.

Оскільки застосовуються різні рівні перевизначення і об'єднання налаштувань, у наведеному нижче прикладі визначені користувачем специфічні налаштування клієнта коригують деякі з налаштувань python-language-server.

{
    "servers": {
        "python": {
            "settings": {
                "pyls": {
                    "plugins": {
                        "pylint": {
                            "enable": true
                        }
                    }
                }
            }
        }
    }
}

На жаль, засоби налаштовування серверів LSP часто не мають належної докладної документації. Лише вивчення коду сервера надає змогу ознайомитися із підходами до налаштовування та переліком доступних параметрів. Зокрема, у наведеному вище прикладі у сервері передбачено підтримку ширшого спектра параметрів у «settings». У документації до іншого клієнта LSP можна знайти приклади для серверів інших мов та відповіді параметри, які доволі просто перетворити на налаштування JSON, які використовуються у нашому клієнті, і які у загальних рисах описано вище.

Придушення діагностики на сервері LSP

Може так статися, що діагностичні дані не є аж надто корисними. Діагностика може бути зайвою, особливо, якщо діагностичних повідомлень надто багато (а також вони належать до одного типу). У деяких випадках, потік повідомлень можна скоригувати за мовою програмування (на сервері). Наприклад, механізм налаштовування clangd уможливлює коригування деяких аспектів діагностики. Втім, загалом, спосіб коригування не завжди очевидний, або коригування взагалі неможливе у бажаний спосіб через обмеження роботи сервера або вади.

Через це, у додатку передбачено підтримку придушення діагностичних повідомлень, подібне до, наприклад, придушення у valgrind. Можна виконати найточніше налаштовування за допомогою ключа «suppressions» у (об'єднаних) налаштуваннях JSON.

{
    "servers": {
        "c": {
            "suppressions": {
                "rulename": ["filename", "foo"],
                "clang_pointer": ["", "clang-tidy", "clear_pointer"],
            }
        }
    }
}

Кожен (коректне) правило може мати довільну назву і бути визначеним масивом довжини 2 або 3, у якому вказано формальний вираз для встановлення відповідності (повній) назві файла, формальний вираз для встановлення відповідності діагностичному тексту та необов'язковий формальний вираз для встановлення відповідності (діапазону початкового коду) тексту, до якого застосовується діагностика.

Окрім вказаних вище точних налаштувань, у контекстному меню вкладки діагностики також передбачено підтримку додавання та вилучення придушень. При цьому відповідність діагностичному тексту встановлюється точно на загальному рівні (будь-який файл) або на локальному рівні (певний вказаний файл). Дані придушень зберігаються у налаштуваннях сеансу і завантажуються з них же.

Діагностика сервера LSP

Одна річ описати як налаштувати (нетиповий) сервер LSP для будь-якої окремої мови програмування, інша ж — зробити так, щоб сервер працював без будь-яких проблем. На щастя, зазвичай, маємо безпроблемну роботу сервера. Втім, іноді можуть виникати проблеми або із певними «тупими» помилками у налаштуваннях або фундаментальні проблеми із самим сервером. Другий варіант може проявляти себе як повідомлення про невдалі спроби запустити сервер, які з'являються на вкладці виведення даних Kate. Втім, такі повідомлення є лише повідомленнями верхнього рівня або повідомленням поступу обробки, а не докладними діагностичними повідомленнями, і навіть можуть не містити даних щодо того, що є, фактично, іншим процесом (сервером LSP).

Звичайним способом діагностики є додавання певних прапорців до команди запуску (сервера мови), які увімкнуть (додаткове) журналювання (до якогось файла або стандартного виведення помилок), якщо цього не зроблено типово. Якщо потім запустити Kate з термінала, можна отримати додаткові дані щодо джерела помилки.

Також дані можна отримати вивченням обміну даними між клієнтом LSP Kate і сервером LSP. Знову ж таки, на останньому, зазвичай, є засоби трасування. Крім того, клієнт LSP надає додаткове діагностичне трасування (до stderr), якщо викликати Kate із належним чином експортованою змінною середовища QT_LOGGING_RULES=katelspclientplugin=true.