天天看點

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

vscode插件快餐教程(5) - 代碼補全

上節我們介紹了lsp的基本架構和協定的三次握手。

下面我們先學習一個最簡單的功能協定:給vscode發送一條通知。

LSP視窗消息

在LSP協定中,跟視窗相關的協定有三條:

  • window/ShowMessage Notification
  • window/showMessage Request
  • window/logMessage Notification

我們可以使用Connection.window.sendxxxMessage函數來向用戶端發送消息。

根據消息程度的不同,分為Information, Warning和Error三個級别。

舉個例子,我們可以在onInitialized,也就是用戶端與服務端三次握手一切就緒之後,向用戶端發一個消息。

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

顯示結果如下:

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

代碼補全

我們用視窗通知熱熱身,測試一下鍊路通不通。下面我們就直奔我們最感興趣的主題之一:代碼補全。

代碼補全的形式其實也很簡單,輸入是一個TextDocumentPositionParams,輸出是一個CompletionItem的數組,這個函數注冊到connection.onCompletion中:

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

代碼補全中用到的主要資料結構如下圖所示:

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

其中kind屬性由一個枚舉定義:

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

大家不要被吓到,我們通過一個簡單的例子看一下,其實基本實作方法還是很簡單的:

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,傳回進一步的資訊。

通過connection.onCompletionResolve方法可以注冊對于completionItem/resolve請求的支援:

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;
    }
)           

運作效果如下:

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

使用參數中的補全位置資訊

輸入參數中會帶有發出補全申請的位置資訊,我們可以根據這個資訊來控制補全的資訊。

我們以一個例子來說明下:

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:

vscode插件快餐教程(5) - 代碼補全vscode插件快餐教程(5) - 代碼補全

繼續閱讀