VS Code Extension – Pinned Panel

前言

自從習慣 Vim 操作之後,就越來越精簡 GUI 介面。接著把 Tab 顯示 workbench.editor.showTabs 也關閉了。編輯視窗瞬時舒爽許多,除了不再擔心切換 Tab 時點選不小心將之關閉,也開始習慣使用快捷鍵 Ctrl/Cmd-P 快速找檔案。接著我才發現一個問題,原本的 Pinned Tab 設計是釘選在 Tab 列的最左側。也就是說,關閉了 Tab 顯示之後,Pin 功能也就如同作廢。其實 VS Code 在側邊欄有一個 OPEN EDITORS 的 View 顯示目前開啟的所有 Editor 視窗,But 就是這個但是,沒有 Pinned Editors!只好自幹了。來看成果:

欸你說 OPEN EDITORS 也會顯示一個圖釘表示釘選!但當你開了一百個 Tab 之後那個釘選就飛向宇宙浩瀚無敵了。所以搞了一個專門顯示釘選檔案的 View,使用起來方便許多,點選即可跳轉,也就不用浪費頂部 Tab Bar 的空間。

Extension Development

VS Code 的 Extension(套件)主要分為以下幾種:

  • Extension (Typescript/Javascript) 一般性套件
  • Color Theme 顏色主題
  • Language Support 新程式語法支援
  • Code Snippets 常用程式模板
  • Keymap 快捷鍵

沒意外,一般都是選擇 Extension,我選用 Typescript(一種強型別的 Javacript),感覺比較厲害。VS Code 不愧為全世界使用者最多(2023 年 zhung 數據)的文字編輯器,連套件的開發手冊都手把手帶你開始

基本上,按照連結的步驟按完,就可以按 開始 Debug 我們的第一個 VS Code Extension 啦!

這次要做的事情其實很簡單:

  • 獲取所有 Pin 的 Editor
  • 顯示在 VS Code 的側邊欄
  • 點選跳轉該檔案

底下一一說明。

Retrieve All Pinned Tabs

翻閱 API 找半天,最後還是求助 Stackoverflow 大神。不曉得有沒有文件再解釋 tabGroup 是什麼,因為 tabGroup 裡面還有一層 tabs 才可以拿到我需要的 Tab 實體。

// https://stackoverflow.com/questions/72772981/how-do-i-get-all-the-tabs-in-a-visual-studio-code-window-as-an-array-of-filename
const tabArray = vscode.window.tabGroups.all[0].tabs;

Register a New Panel Called “Pinned Files”

對 npm 不是很熟,但 VS Code 會使用 Package.json 來管理套件需要的資源,例如所有註冊的 Command、View 等等。新增以下欄位,請注意 views 裡面的 explorer 是 VS Code內建的檔案總管 Panel。

{
    "activationEvents": [
      "onView:packagePinnedExplorer"
    ],
    "contributes": {
        "views": {
            "explorer": [
                {
                    "name": "Pinned Files",
                    "id": "packagePinnedExplorer"
                }
            ]
        }
    }
}

然後在 Code 裡面註冊 ID 的實體。

const pinnedProvider = new PinnedFilesProvider()
const tree = vscode.window.createTreeView('packagePinnedExplorer', {
    treeDataProvider: pinnedProvider,
    showCollapseAll: false
});

這個 view 做的事情很簡單,就是提供一個 vscode.TreeDataProvider 讓 VS Code 去顯示 Tree View。詳細實作可以參考我 Github 上的原始碼

Click Item to Jump to Editor

這次應該就這裡卡關最久,因為我不知道要監聽哪一個 Event,也不知道要如何監聽事件。搞了半天終於找到了一個暫解。

tree.onDidChangeSelection(async e => {
    let t = e.selection[0].tab;
    await vscode.window.showTextDocument(t.input.uri);
});

這有一個 Bug 就是當 Selection 沒有變化的時候,無法跳轉。目前是可以先點旁邊,再點選以繞過此問題,未來需要找個更好的寫法。

Update View When Pin Changed

還有一個很重要的,當解除釘選、或是新加入釘選的時候,需要更新列表。

vscode.window.tabGroups.onDidChangeTabs(unused => {
    pinnedProvider.refresh();
});

需要額外在 PinnedFilesProvider 中實作 Refresh 方法。

export class PinnedFilesProvider implements vscode.TreeDataProvider {
    // ...

    private changeEvent = new vscode.EventEmitter();

    public get onDidChangeTreeData(): vscode.Event {
        return this.changeEvent.event;
    }

    refresh(): void {
        this.changeEvent.fire();
    }
}

搞定!雖然都是一些簡單的實作,但終於完成自己的第一個 VS Code 套件,開心!接下來就要發佈給全世界使用啦 🤩

Publish to Extension Marketplace

不得不說,發佈這一步真的比 Sublime Text 簡單的多。再次來參考官方 Publish Extension 手冊

要先用 npm 安裝轉譯程式 @vscode/vsce ,以將 Typescript 原始碼製作成 VSIX 檔案(VS Code 套件的離線安裝檔案)。

$ vsce package
# myExtension.vsix generated

雖然直接使用 vsce publish 指令可能會比較方便,但接下來我還是選擇手動上傳此檔案。會需要一個帳號來管理自己發佈的套件。

  1. 前往 VS Code Extension Marketplace,註冊一個新的帳號,也可以選用 Github 授權登入。然後就可以再右上角選擇 [Publish extensions]。
  2. 接著需要新增一個 Publisher 發布商,填好必要資訊就可以了。
  3. 點選 [+ New extension] > [Visual Studio Code],上傳,點擊 [Upload]。
  4. 等一會兒,你的套件就可以在全世界的 VS Code 中搜尋到啦。

撒花 🎉

Extension Page

Pinned Panel

Source Code

ukyouz/VSCode-PinnedPanel

 

References