Автор Xulun

В статье Быстрый запуск подключаемых модулей VSCode: протокол языкового сервера мы представили базовую структуру и некоторые преимущества протокола LSP, а также принцип трехстороннего установления связи, связанный с использованием протокола.

В этой части этой серии руководств мы начнем с простейшего функционального протокола из множества различных протоколов LSP, который используется для «отправки уведомления в VSCode».

Сообщение окна LSP

Что касается протокола LSP, вы можете видеть, что предоставляются три протокола, связанных с окнами, а именно следующие протоколы:

  • окно / Уведомление о ShowMessage
  • window / showMessage Запрос
  • window / logMessage Уведомление

Мы можем использовать функцию Connection.window.sendxxxMessage для отправки сообщений клиенту. В зависимости от степени серьезности сообщения можно разделить на три различных уровня: информация, предупреждение и ошибка.

Например, мы можем отправить сообщение клиенту после завершения трехстороннего рукопожатия между клиентом и сервером (то есть после onInitialized).

connection.onInitialized(() => {
    connection.window.showInformationMessage('Hello World! form server side');
});

Результат показан следующим образом:

Автозавершение кода

Давайте «разогреемся» с помощью окна уведомления, чтобы проверить сбой соединения. Затем мы переходим непосредственно к одной из тем, которые нас больше всего интересуют: автозавершение кода.

Форма завершения кода на самом деле очень проста. Входными данными является TextDocumentPositionParams, а выходными данными - массивом CompletionItem. Эта функция зарегистрирована в connection.onCompletion:

connection.onCompletion(
    (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {});

Основная структура данных, используемая при автозавершении кода, показана на следующем рисунке:

Свойство «kind» определяется перечислением, которое является одним из многих доступных типов.

Не позволяйте этому вас запугать. Давайте посмотрим на простой пример. На самом деле, базовый метод реализации довольно прост:

connection.onCompletion(
    (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
        connection.console.log('[xulun]Position:' + _textDocumentPosition.textDocument);
        return [
            {
                label: 'TextView',
                kind: CompletionItemKind.Text,
                data: 1
            },
            {
                label: 'Button',
                kind: CompletionItemKind.Text,
                data: 2
            },
            {
                label: 'ListView',
                kind: CompletionItemKind.Text,
                data: 3
            }
        ];
    }
)

Детали завершения

Помимо textDocument/completion для заполнения информации, LSP также поддерживает запрос completionItem/resolve. И вход, и выход CompletionItem, и возвращается дополнительная информация.

Поддержка запроса completionItem/resolve может быть зарегистрирована методом connection.onCompletionResolve:

connection.onCompletionResolve(
    (item: CompletionItem): CompletionItem => {
        if (item.data === 1) {
            item.detail = 'TextView';
            item.documentation = 'TextView documentation';
        } else if (item.data === 2) {
            item.detail = 'Button';
            item.documentation = 'JavaScript documentation';
        } else if (item.data === 3) {
            item.detail = 'ListView';
            item.documentation = 'ListView documentation';
        }
        return item;
    }
)

Эффект такой:

Информация о местоположении в параметрах завершения

Входной параметр содержит информацию о местоположении для отправки запроса на завершение. Мы можем использовать эту информацию для управления информацией, которую необходимо заполнить.

Вот пример:

connection.onCompletion(
    (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
        
        return [
            {
                label: 'TextView' + _textDocumentPosition.position.character,
                kind: CompletionItemKind.Text,
                data: 1
            },
            {
                label: 'Button' + _textDocumentPosition.position.line,
                kind: CompletionItemKind.Text,
                data: 2
            },
            {
                label: 'ListView',
                kind: CompletionItemKind.Text,
                data: 3
            }
        ];
    }
)

В это время мы не только завершаем имя виджета, но также добавляем текущий номер строки или номер столбца.

Ниже приводится операция завершения Button. Текущий номер строки будет добавлен к информации о завершении. Завершение запускается в строке 934, поэтому подсказка для завершения изменяется на Button933:

Первоисточник