xmake-vscode插件開發過程記錄

最近打算給xmake寫一些IDE和編輯器的集成插件,發現vscode的編輯器插件比較容易上手的,就先研究了下vscode的插件開發流程,并且完成了xmake-vscode插件的開發。

我們先來看幾張最后的效果圖:

語法高亮和自動補全

狀態欄

statusbar

要實現上面的效果,其實并不復雜,首先我們先來簡單介紹下,vscode的插件開發的基本流程:

安裝插件開發環境

安裝cnpm

由于國內環境比較復雜,直接用npm安裝也許很慢或者訪問不穩定,因此這里先安裝了cnpm去默認使用淘寶的鏡像源。

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

創建空工程

通過cnpm去安裝yo工具,用來創建一個vscode插件的空工程

$ cnpm install -g yo generator-code
$ yo code

大體的源碼結構如下:

選擇創建項目后有四個輸入和一個選擇:

  • 輸入你擴展的名稱 xmake-vscode
  • 輸入一個標志(項目創建的文件名稱用這個)xmake-vscode
  • 輸入對這個擴展的描述
  • 輸入以后要發布用到的一名稱(和以后再發布時候有一個名字是對應上的)tboox
  • 是問你要不要創建一個git倉庫用于版本管理

創建完成后的空工程,我們可以用vscode直接打開,然后進行調試加載運行下:

加載起來后,敲F1打開命令窗口,運行默認的hello world測試命令:


到此,一個簡答的demo插件就搞定了,接下來我們簡單介紹下如何發布這個插件到vscode的market上去。

創建發布者

首先我們需要在marketplace.visualstudio.com上注冊一個賬號,創建一個發布者,這里我取名為tboox

然后,我們需要在自己的賬號里面,添加一個Personal Access Token(地址:https://[your name].visualstudio.com/_details/security/tokens,注意Token只顯示一次,最好自己保存一份)

接著,我們安裝下vsce這個工具,用于vscode的插件工程打包編譯和發布。

$ cnpm install -g vsce

安裝好vsce后,我們先創建一個發布者,這里為tboox,輸入剛剛market賬號里面提供的token進行綁定。

$ vsce create-publisher (publisher name)

構建發布

最后,只需要通過下面命令進行打包或者發布就行了,如果僅僅打個本地包,拖入vscode加載測試,可以運行:

$ vsce package

這將會生成一個類似xmake-vscode-0.0.1.vslx的插件包文件,用vscode可直接加載運行。

如果,我們已經開發完了插件,想要發布到market市場,可以執行:

$ vsce publish [version]

這個時候,我們就可以在xmake-vscode on marketplace上看到你的插件了,用戶也可以直接通過vscode進行搜索和安裝使用。

插件開發詳解

插件的加載機制

插件通過工程根目錄extension.json中配置的activationEvents進行觸發,例如:

{
    "activationEvents": [
        "workspaceContains:xmake.lua",
        "onCommand:xmake.sayHello"
    ]
}

當vscode打開帶有xmake.lua的目錄或者執行xmake.XXX相關命令的時候,都會觸發加載xmake-vscode插件,然后調用src/extension.ts中的activate入口函數,進行插件的加載和初始化。

export function activate(context: vscode.ExtensionContext) {

    let disposable = vscode.commands.registerCommand('xmake.sayHello', () => {
        vscode.window.showInformationMessage('Hello XMake!');
    });

    context.subscriptions.push(disposable);
}

上述代碼,在加載插件的時候,注冊sayHello命令,去顯示Hello XMake!提示信息。

創建自定義輸出

vscode通過創建OutputChannel來輸出自己的日志信息,代碼如下:

import * as vscode from 'vscode';

let log = vscode.window.createOutputChannel("xmake/log");
log.show();
log.appendLine("hello xmake!");

在創建的時候可以指定一個label名,用于區分不同的輸出通道,最后顯示的結果如下:

需要注意的是,必須執行log.show(),輸出才會被顯示出來,并且輸出行為是帶緩存刷新的,并不會實時輸出,也不支持色彩高亮輸出。

創建和控制終端

之前,xmake-vscode就是采用channel的方式來輸出xmake的構建信息,效果不是很理想,因此后來改用了終端直接執行的方式,可以看下下面的效果圖:

那如何控制終端,執行自己的命令呢,其實也非常簡單:

let terminal = vscode.window.createTerminal({name: "xmake"});
terminal.show(true);
terminal.sendText("xmake");

上面的代碼,通過創建一個label名為xmake的獨立終端,然后發送執行命令:xmake,去讓終端執行xmake進行項目的構建,當然如果要顯示出來,還是要先調用下terminal.show(true)

添加和讀取全局配置

xmake-vscode里面增加了一些全局vscode配置項,用于控制xmake-vscode插件的行為,配置清單是在package.json文件中進行描述的,例如:

{
    "configuration": {
        "type": "object",
        "title": "XMake configuration",
        "properties": {
            "xmake.logLevel": {
                "type": "string",
                "default": "normal",
                "description": "The Log Level: normal/verbose/minimal",
                "enum": [
                    "verbose",
                    "normal",
                    "minimal"
                ]
            },
            "xmake.buildDirectory": {
                "type": "string",
                "default": "${workspaceRoot}/build",
                "description": "The Build Output Directory"
            },
            "xmake.androidNDKDirectory": {
                "type": "string",
                "default": "",
                "description": "The Android NDK Directory"
            }
        }
    }
}

上述配置,增加了三個配置項,都在xmake.域下面,可在vscode配置中直接搜索xmake相關字樣就能方便找到。

讀取配置也很方便,只要獲取xmake相關域配置,進行讀取就行了:

const config = vscode.workspace.getConfiguration('xmake');
config.get("buildDirectory");

創建狀態欄

狀態欄上的按鈕是可以響應之前創建的那些命令的,例如:xmake.sayHello等,下面我們在狀態欄上創建一個debug按鈕,用來調試運行xmake構建的程序:

let debugButton = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 4.5);

debugButton.command = 'xmake.onDebug';
debugButton.text = `$(bug)`;
debugButton.tooltip = "Debug the given target";
debugButton.show();

createStatusBarItem中第二個參數4.5用于控制按鈕在狀態欄上的布局順序,創建好后,再設置下一些基礎屬性就行了,這里按鈕的文本直接通過$(bug)設置了一個圖標來顯示,更加的直觀。

更多vscode內置支持的圖標,可以自己從octicons上面去找。

點擊這個按鈕,將會觸發xmake.onDebug命令,然后在終端上執行xmake run -d命令,去運行調試程序。

添加選項輸入列表

xmake-vscode的狀態欄上,我們還增加了幾個快速配置的狀態按鈕,用于快速切換不同的平臺、架構、編譯模式,例如:

這個時候,需要有個選項選擇列表的支持,在點擊按鈕后,列出可以選擇的幾個選項,然后選擇切換,那如何創建這個選項列表呢,直接上代碼:


// 初始化選項列表清單
let items: vscode.QuickPickItem[] = [];
items.push({label: "linux", description: "The Linux Platform"});
items.push({label: "macosx", description: "The MacOS Platform"});
items.push({label: "windows", description: "The Windows Platform"});
items.push({label: "android", description: "The Android Platform"});
items.push({label: "iphoneos", description: "The iPhoneOS Platform"});
items.push({label: "watchos", description: "The WatchOS Platform"});
items.push({label: "mingw", description: "The MingW Platform"});
items.push({label: "cross", description: "The Cross Platform"});

// 顯示選項列表,提示用戶選擇
const chosen: vscode.QuickPickItem|undefined = await vscode.window.showQuickPick(items);
if (chosen) {

    // 獲取選擇后的結果,然后更新狀態欄按鈕文本
    platButton.text = chosen.label;
}

自定義語法高亮

語法高亮完全可以通過配置文件來搞定,不用寫代碼,當然也可以在代碼中動態配置,這樣稍微繁瑣些。

xmake-vscode里面需要處理工程xmake.lua描述文件的語法高亮,因此這邊在package.json里面先定義了一個叫xmake的語言類型,如果編輯器打開xmake.lua文件,就會對其進行語法高亮處理。

{
    "contributes": {
        "languages": [
            {
                "id": "xmake",
                "filenames": [
                    "xmake.lua"
                ],
                "aliases": [
                    "XMake"
                ],
                "configuration": "./languages/xmake-configuration.json"
            }
        ],
        "grammars": [
            {
                "language": "xmake",
                "scopeName": "source.xmake",
                "path": "./languages/xmake-grammars.json"
            }
        ]
    }
}

跟語法高亮相關的描述,都放置在/languages/xmake-grammars.json中,用json來描述,我們也可以用xml的格式來描述,但是這樣可讀性不是很好。

xmake-grammars.json中的描述規則,我們摘錄自lua的grammars文件,因為xmake.lua本身就是基于lua語法的,例如,我們匹配'xxx'單引號字符串的規則,進行字符串的高亮輸出。

{
    "begin": "'",
    "beginCaptures": {
        "0": {
            "name": "punctuation.definition.string.begin.xmake"
        }
    },
    "end": "'",
    "endCaptures": {
        "0": {
            "name": "punctuation.definition.string.end.xmake"
        }
    },
    "name": "string.quoted.single.xmake",
    "patterns": [
        {
            "include": "#escaped_char"
        }
    ]
}

自動補全的實現

代碼的自動提示和補全比較麻煩下,需要寫個自定義的class,通過languages進行注冊:

vscode.languages.registerCompletionItemProvider("xmake", new Completion());

這里我們定義了一個Completion類,注冊到xmake語言上去,xmake語言定義,就是剛才講的在package.json中的配置。

然后我們實現下這個Completion類:

export class Completion implements vscode.CompletionItemProvider {

    // 匹配當前輸入,提供需要補全的候選文本列表
    public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable<vscode.CompletionItem[]> {

        // 獲取當前輸入的單詞文本
        let wordAtPosition = document.getWordRangeAtPosition(position);
        var currentWord = '';
        if (wordAtPosition && wordAtPosition.start.character < position.character) {
            var word = document.getText(wordAtPosition);
            currentWord = word.substr(0, position.character - wordAtPosition.start.character);
        }

        // 猜測匹配結果,返回候選列表
        return new Promise(function (resolve, reject) {
            Promise.all([
                getLuaKeywordsSuggestions(currentWord),
                getXMakeCommandsSuggestions(currentWord)
            ]).then(function (results) {
                var suggestions = Array.prototype.concat.apply([], results);
                resolve(suggestions);
            }).catch(err => { reject(err); });
        });
    }

    // 這里可以對剛剛返回的候選文本列表在做二次處理,例如:增加詳細的文檔描述信息
    public resolveCompletionItem(item: vscode.CompletionItem, token: vscode.CancellationToken): Thenable<vscode.CompletionItem> {
        
        // 對每個候選文本增加文檔描述
        return new Promise(function (resolve, reject) { 
            item.documentation = "xxxxxxxxxxx";
            resolve(item);
         });
    }
}

這部分代碼比較多,就不完全貼出來了,完整實現,可參考:completion.ts

結語

本文講述的一些vscode插件代碼都來自xmake-vscode,有興趣的同學可以直接參考源碼,寫個自己的插件。

原文出處:http://tboox.org/cn/2017/10/11/xmake-vscode/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容