插件機制詳述_VSCode插件開發筆記1

一.擴展能力
VS Code插件不適合作UI定製,好比Atom的tool-bar 在VS Code很難實現:javascript

插件機制詳述_VSCode插件開發筆記1

提供了豐富的擴展能力模型,但不容許插件直接訪問底層UI DOM(也就是說插件難以改變IDE外觀,UI定製受限),這是出於方便底層持續優化考慮:css

With VS Code, we’re continually trying to optimize use of the underlying web technologies to deliver an always available, highly responsive editor and we will continue to tune our use of the DOM as these technologies and our product evolve.

UI DOM這一層可能會隨着優化頻繁變更,VS Code不但願這些優化項受限於插件依賴,因此乾脆把UI定製能力限制起來java

除UI定製以外的,IDE相關的功能型特性都是支持擴展的,如基礎的語法高亮/API提示、引用跳轉(轉到定義)/文件搜索、主題定製,高級的debug協議等等node

P.S.實際上,非要擴展UI,也是有辦法的(逃出插件運行環境,但要費很多力氣),具體見access electron API from vscode extension,後續筆記會詳細介紹git

二.運行環境
爲了性能與兼容性,插件在獨立的進程(稱爲extension host process)中運行,而且不容許直接訪問DOM,因此提供了一套內置的UI組件,好比智能提示(IntelliSense)github

因此插件崩潰或無響應不影響IDE正常運行,例如:web

// ref: my-extension/src/extension.ts
export function activate(context: vscode.ExtensionContext) {
  // hang up
  while (true);
}

一個插件的死循環並不影響IDE的正常使用和其它插件的加載/激活,但在進程列表可以看到Code Helper的CPU佔用接近100%,進程級沙箱保證了插件機制的穩定性npm

三.核心理念
穩定性:插件隔離
插件可能會影響啓動性能和IDE自身的穩定性,因此經過進程隔離來解決這個問題,插件運行在獨立的進程中,不影響IDE及其啓動時間編程

這樣作是從用戶角度考慮的,但願用戶對IDE擁有徹底的控制力,不管插件在作什麼,都不影響IDE基本功能的正常使用json

P.S.extension host process是個特殊的Node進程,可以訪問VS Code擴展API,VS Code也對這種進程提供了debug支持

性能:插件激活
插件都是懶加載的(as late as possible),只在特定場景才加載/激活,全部在此以前也不耗費內存等資源

實現上是插件註冊特定激活事件(activation events),由IDE來觸發執行,好比markdown插件只在用戶代開md文件時才須要激活

激活方式
插件有6種激活方式:

onLanguage:${language} 打開特定語言的文檔
onCommand:${command} 經過Command Palette執行特定命令
onDebug 進入調試模式
workspaceContains:${toplevelfilename} 打開的文件夾裏含有特定文件
onView:${viewId} 展開指定view

  • 打開IDE就激活
    除"activationEvents": ["*"]外都是條件激活,只在特定場景或知足特定條件時才加載/激活插件

插件清單文件
清單文件用來描述插件的meta信息,直接把package.json做爲清單文件,並增長了一些特有字段,好比觸發插件加載的激活事件(activation events)、插件想要加強的擴展點(contribution points)

IDE在啓動過程當中掃一遍插件清單文件,UI相關的就擴展UI,UI無關的就把擴展點與插件功能關聯起來

另外,因爲插件的執行環境是Node進程,因此npm package都是可用的,依賴模塊一樣聲明在package.json裏。注意,用戶安裝插件時不會自動npm install,因此須要在發佈插件前把依賴模塊打包進去,具體見Installation and Packaging

P.S.擴展點相似於AOP裏的Join point(鏈接點),即「容許在這裏擴展/加強」,好比新增一個自定義命令,就是對commands擴展點的加強

manifest
// package.json
{
  // 插件名稱
  "name": "my-extension",
  // 顯示名稱
  "displayName": "MyExtension",
  // 描述信息
  "description": "An awesome vscode  extension",
  // 版本號 semver格式
  "version": "0.0.1",
  // 在插件市場展現的圖標
  "icon": "img/icon.png",
  // 發佈者名字
  "publisher": "ayqy",
  // vscode版本要求
  "engines": {
    "vscode": "^1.19.0"
  },
  // 所屬分類,可選Languages, Snippets, Linters, Themes等等
  "categories": ["Other"],
  // 加載/激活方式
  "activationEvents": ["onLanguage:javascript"],
  // 入口文件路徑
  "main": "./out/extension",
  // 註冊擴展點關聯
  "contributes": {
    "languages": [
      {
        "id": "javascript",
        "aliases": ["JavaScript", "javascript"],
        "extensions": [".js"]
      }
    ]
  }
}

P.S.完整的見Extension Manifest File – package.json

extension.ts/activate只觸發一次,根據package.json聲明的activationEvents來觸發,觸發條件能夠是打開特定語言的文件,或者執行特定命令。激活以後,直到IDE被關閉/崩潰纔會觸發extension.ts/deactivate,因此通常用法是:

activate: 插件被激活,初始化功能模塊單例(只執行一次)

deactivate: IDE即將關閉,清理現場,但不宜作太耗時的操做,由於聽說最多隻等待10s

擴展點
即支持的擴展類型,都聲明在package.json/contributes下,包括:

configuration 插件配置項,用戶能夠經過Settings設置
configurationDefaults 插件配置項默認值
commands 添加命令,用戶能夠經過Command Palette輸入特定命令激活插件功能
menus 添加與命令關聯的菜單項,用戶點擊菜單項時執行對應命令
keybindings 添加與命令關聯的快捷鍵,用戶按下特定快捷鍵時執行對應命令
languages 與文件類型創建關聯或擴展新語言,用戶打開(知足某些要求的)特定文件類型時執行對應命令
debuggers 添加debugger,經過VS Code debug協議與IDE通訊
breakpoints 配合debuggers,聲明對debugger支持的(編程)語言類型
grammars 新增TextMate語法描述,語法高亮
themes 添加定製主題
snippets 添加代碼片斷
jsonValidation 添加json格式校驗
views 新增左側文件查看器視圖和調試視圖分欄
problemMatchers 添加錯誤匹配,從lint結果解析出error,warning等
problemPatterns 配合problemMatchers,定義匹配模式
menus是惟一的UI擴展官方途徑,支持擴展的菜單具體以下:

Command Palette搜索框下方菜單 commandPalette
文件查看器右鍵菜單 explorer/context
編輯器
右鍵菜單 editor/context
標題欄菜單 editor/title
標題欄右鍵菜單 editor/title/context
調試視圖
調用棧右鍵菜單 debug/callstack/context
SCM(源碼管理)視圖
標題欄菜單 scm/title
文件分組菜單 scm/resourceGroup/context
文件狀態菜單 scm/resource/context
文件變更菜單 scm/change/title
左側視圖
文件查看器分欄 view/title
調試視圖分欄 view/item/context
P.S.都是些不起眼的位置,大刀闊斧的UI定製是不支持的,好比想在左端側邊欄(Activity Bar)加個Icon都是作不到的

標題欄上的菜單擴展支持自定義icon,但定義方式比較奇怪,例如:

"commands": [{
  "command": "markdown.showPreviewToSide",
  "title": "%markdown.previewSide.title%",
  "category": "Markdown",
  "icon": {
    "light": "./media/PreviewOnRightPane_16x.svg",
    "dark": "./media/PreviewOnRightPane_16x_dark.svg"
  }
}],
"menus": {
        "editor/title": [
            {
                "command": "markdown.showPreviewToSide",
                "when": "editorLangId == markdown",
                "alt": "markdown.showPreview",
                "group": "navigation"
            }
  ]
}

給command定義icon,menu關聯到command,而後menu展現對應的icon

擴展API
環境隔離讓嚴格限制插件可用API變得容易不少,插件只能訪問IDE提供的擴展性API,不能胡亂搞事情(好比修改UI DOM和樣式,官方支持的主題定製項除外)

API設計原則
插件API遵循一些原則:

基於Promise:異步操做都用Promise來描述

取消token:傳入CancellationToken做爲額外參數來檢查取消狀態,以及接收取消通知

可釋放式資源管理:持有的資源都須要手動釋放,例如事件監聽,命令,UI交互等

事件API:調用訂閱方法(on[Will|Did]VerbNoun)傳入listener(接收event參數)返回Disposable

嚴格空檢查:經過TypeScript嚴格區分undefined和null

P.S.關於「可釋放式」(Disposable)的更多信息,請查看Dispose pattern

API概覽
API按命名空間組織,全局命名空間以下:

commands 執行/註冊命令,IDE自身的和其它插件註冊的命令均可以,如executeCommand
debug 調試相關API,好比startDebugging
env IDE相關的環境信息,好比machineId, sessionId
extensions 跨插件API調用,extensionDependency聲明插件依賴
languages 編程語言相關API,如createDiagnosticCollection, registerDocumentFormattingEditProvider
scm 源碼版本控制API,如createSourceControl
window 編輯器窗體相關API,如onDidChangeTextEditorSelection, createTerminal, showTextDocument
workspace 工做空間級API(打開了文件夾纔有工做空間),如findFiles, openTextDocument, saveAll
好比能夠經過workspace.findFiles + languages.registerDefinitionProvider實現Haste的全局模塊引用跳轉支持

另外,一些API以命令形式提供(即上面提到的「IDE自身的」命令),例如vscode.previewHtml、vscode.openFolder、editorScroll等等

基於協議的擴展
插件進程與IDE之間經過特定協議來通訊,實現上是以JSON形式的stdin/stdout來通訊

這種模式更強大的一點是:插件能夠用任意語言來實現,只要遵照這套約定的通訊協議便可

四.語言相關擴展
經過配置文件來支持語法高亮、代碼片斷和智能括號匹配,更復雜的經過擴展API或language server來作

配置型擴展
語法高亮:基礎支持區分字符串、註釋、關鍵字等語法角色,高級支持變量、函數引用等語義區分

代碼片斷:snippets快捷輸入,基礎支持簡單佔位符,高級支持嵌套佔位符

智能括號匹配:高級支持自動補充成對出現的東西,好比括號、引號、跨行註釋等

注意,語言擴展VS Code支持標準Text Mate Grammar(tmLanguage格式),好比Monaco Editor的非主流Monarch-style友好不少,具體見Colorization Clarification

編程型擴展
簡單配置搞不定的,都經過擴展API(寫插件)來實現,有2種方式:

實現language server protocol與IDE通訊,徹底獨立

註冊Provider提供自定義能力,相似於hook的方式

使用上,第一種麻煩但更強大靈活,第二種方便直接但沒那麼靈活。支持的擴展能力以下:

hover提示:基礎支持類型、文檔等信息,高級支持方法簽名語法高亮

補全提示:高級支持在補全提示項旁邊展現額外信息

檢查報錯:基礎支持保存時對打開的文件內容檢查報錯,高級支持對打開的文件目錄裏的任意資源檢查報錯

方法簽名:基礎支持在方法簽名中包含參數說明文檔

跳轉到定義:基礎支持存在多處定義時都展現出來

引用查找:基礎支持返回全部引用處的具體位置

選中查找高亮:基礎支持返回當前文檔的全部相同引用

方法/變量聲明目錄:基礎支持返回文檔中聲明的全部標識符,及其定義位置

快速修復:對Warning和Error給出建議作法,快捷修復。基礎支持糾錯動做,高級支持修改源碼,好比重複代碼提出函數

上下文操做選項:容許根據用戶處代碼上下文,提供額外的信息與可操做選項。基礎支持展現,高級能夠添加自定義命令

重命名:基礎不支持按引用重命名,高級支持工做空間下跨文件重命名

代碼格式化:基礎不支持代碼格式化,高級支持全文/選中/輸入中格式化

五.開發步驟
環境要求
VS Code

Yeoman與Yo Code – Extension Generator:npm install -g yo generator-code一步搞定

步驟
經過腳手架生成項目模版:

yo code
命令交互選擇插件類型:

New Extension (TypeScript)
New Extension (JavaScript)
New Color Theme
New Language Support
New Code Snippets
New Extension Pack

建議TypeScript,其它都是字面意思,其中Extension Pack(插件包)比較有意思,即插件組裝成的插件,相似於React Native的Nuclide

輸入插件名稱等meta信息,就獲得一個插件項目,而後用VS Code單獨打開該項目(工做空間不能有其它項目目錄),F5啓動debug進入插件調試

插件入口文件是my-extension/src/extension.ts,項目結構規範能夠參照VS Code內置插件:

// ref: https://github.com/Microsoft/vscode/tree/master/extensions/markdown
markdown/
  media/
    *.svg
    *.css
  snippets/
    markdown.json
  syntaxes/
    *.tmLanguage
  src/
    features/
      *Provider.ts
    typings/
      *.d.ts
    commandManager.ts
    commands.ts
    logger.ts
    markdownEngine.ts
    security.ts
    telemetryReporter.ts

六.打包發佈
提供了CLI工具,vsce:

npm install -g vsce
打包
進入插件目錄,打包成.vsix文件:

cd my-extension
vsce package

會獲得一個my-extesion.vsix本地包(包括node_modules依賴),而後不想公開的話,本身想辦法傳播安裝,由於不像npm registry,能夠手動部署一份,在內網環境放私有插件,Visual Studio Marketplace(VS Code插件市場)沒有這麼開放的心態:

If you want to share your extension with others privately, you can send them your packaged extension .vsix file.

(見Sharing Privately with Others)

沒有辦法部署一套Visual Studio Marketplace,因此只能想辦法手動解決插件更新問題,好比自動下載/提示安裝

發佈
要發佈到插件市場的話,須要作幾件事情:

註冊Visual Studio Team Services帳號

進入Security頁面建立個Personal Access Token

vsce create-publisher (publisher name)命令新增publisher

vsce login (publisher name)命令登陸

vsce publish -p <token>命令發佈

具體見Publishing Extensions

參考資料Extending Visual Studio Code

相關文章
相關標籤/搜索