iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
1

大家好,我是韋恩,今天我們來演練一下如何在vscode裡面跟使用者做對答互動,使用GUI互動的方式滿足實務上的需求與功能。

使用者流程與情境說明


想像一下,我們正在terminal裡面,正想要使用操作git完成以下幾件事情:

  1. 查看當前head處在哪個branch,列出所有當前的branch。
$ git branch
  1. 創建一個新的branch,並且checkout到這個branch中。
$ git checkout -b newBranch  
  1. 過一段時間後,再次檢視head已經處於新的branch上
$ git branch

我們要在terminal裡面輸入這幾個指令。

現在,我們想讓使用者可以在VSCode裡面舒服的完成這幾件事情,我們的Extension可以這樣做,幫助使用者更好地完成工作。

  1. 在vscode裡面的status bar的ui上創建一個item呈現當前branch的狀況

  2. 在使用者點擊status item的時候,跳出可創建的選項跟其他操作(此處我們點選Create new branch)

  3. 跳出輸入框讓使用者輸入branch name

  4. 使用者輸入branch名稱後按enter,幫使用者創建一個branch並checkout到新的branch上。

  5. 刷新status item的狀態至新的branch上。

以上是一個真實extension使用與互動的場景。VSCode提供的Git Extension的功能已經實現了這個功能。

現在,讓我們來試著實現一下這個feature,在練習過程中了解熟悉這一系列api的使用方式吧!

Day10練習:打造在VSCode裡的Git使用者互動流程


首先,讓我們了解下如何在statusbar上註冊item,並呈現文字。先讓我們看一下這個範例

  • 在extension.ts裡註冊statusbar-item,設定item置最左邊,並呈現status文字。
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

	let item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10000);
	item.text = 'day10-master';
    item.show();
	context.subscriptions.push(item);
}

上面這段程式中,我們使用createStatusBarItem這個api,在使用任何api之前,先讓我們透過自動補全了解一下這個api要怎麼使用。

當我們要create一個StatusBarItem。我們可以傳給create方法StatusBarAlignment這個enum的left或right值,告訴vscode這個item要放置於左邊還是右邊,並且可以設定優先度數值決定順序,這裡我們設數字10000,我們的statusItem的優先度比所有item更高,好讓item置於最左邊。

之後,我們設定text為'day10-master',再用item底下的show方法顯示item。

此時按F5,執行結果如下:

  • 在statusbar item上綁定命令:

已經可以顯示資料了,下一步,我們要讓使用者可以在點擊item時觸發事件。statusbarItem允許我們綁定一個註冊好的Command的Id,在點擊時即會執行這個命令。因此我們註冊一個day10-userinput-api.updateItem的command,並在command執行後自動刷新item的狀態資料文字,如下所示:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

	const updateCommandId = 'day10-userinput-api.updateItem';

	let item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10000);
	item.text = 'day10-master';
	item.command = updateCommandId;
	item.show();

	let updateItemCommand = vscode.commands.registerCommand(updateCommandId, () => {
		item.text = 'day10-updatedItemText';
	});

	context.subscriptions.push(item, updateItemCommand);
}

現在再按F5並且點擊我們設定好的statusBarItem,我們可以看到已經刷新文字為day10-updatedItemText了。

  • 呈現下拉選單讓使用者點擊,並觸發下一步事件:

現在我們要改為在使用者點擊item時展開下拉選單,選單裡要展示git的branch名字,為此,我們設計了一個MockGit的class模擬git的操作與branch切換,程式碼如下:

class MockGit {

	private head = 0;

	private branchs = ['day10-master'];
	
	public get currentBranch() {
		return this.branchs[this.head];
	}

	public checkout(branchName: string) {
        this.head = this.branchs.findIndex(n => n === branchName);
        return this.currentBranch;
	}

	public branch(newBranch?: string) {
		if(newBranch) {
			this.branchs.push(newBranch);
		}
		return this.branchs;
	}
}

有了git後,我們再來看一下如何創建下拉選單,

在vscode,我們可以使用showQuickPick這個api方法,

透過自動補全,我們可以了解這個showQuickPick會回傳一個thenable,也就是一個可像promismㄧ樣供操作的物件。當user點擊下拉選單,我們即會取得像promise一樣resolve後的回傳值,這裡我們會使用await來取得user輸入的選項。

再來,我們將其封裝為一個可以重複使用的方法,方便在不同的地方使用。

const dropdown = async (dropdownItems: string[]) => await vscode.window.showQuickPick(dropdownItems, {
	canPickMany: false,
	placeHolder: `Select your git action`,
});

好,現在我們已經有了下拉選單的創建方法,讓我們註冊點擊item後的命令,顯示下拉選單以及git的branch選項吧:

 export function activate(context: vscode.ExtensionContext) {

	const updateCommandId = 'day10-userinput-api.updateItem';

	const git = new MockGit();

	let item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10000);
	item.text = git.currentBranch;
	item.command = updateCommandId;
	item.show();

	let updateItemCommand = vscode.commands.registerCommand(updateCommandId, async () => {
		const answer = await dropdown([
			'Create new branch',
			...git.branch()
		]) || '';
		vscode.window.showInformationMessage(answer);
	});

	context.subscriptions.push(item, updateItemCommand);
}

已經完成了下拉選單,現在我們執行extension,並點擊statusItem,會看到展示的選單!

顯示了下拉選單,再讓我們點擊第一個create branch按鈕吧,看看我們會取得什麼樣的執行結果。

我們會取得user點擊下拉選單的選項,如下所示:

  • 依據使用者選項,觸發下一步事件:

前面我們提供了使用者兩個類型的選項,一種是Create new branch,另一種則是當前已經有的branch名稱。

現在我們就根據這兩類結果來做不同處理。

針對第一種,我們會使用VSCode的showInputBox方法創造一個input給使用者輸入,並設定placeHolder的文字,如下所示:

const input = async (placeHolder: string) => await vscode.window.showInputBox({
    placeHolder
}) || '';

有了Input之後,我們就可以使用它取得user想新增的branch名稱,相關程式碼如下:

let updateItemCommand = vscode.commands.registerCommand(updateCommandId, async () => {

    const answer = await dropdown([ 'Create new branch', ...git.branch()]) || '';

    if(answer === 'Create new branch') {

        const newBranchName = await input('New Branch Name');

        git.branch(newBranchName);

        item.text = git.checkout(newBranchName);

        vscode.window.showInformationMessage(`Create new branch ${newBranchName}`);

    } else if(answer !== '') {
        ...
    }
}

完成上面邏輯後,我們在else if分支這邊裡撰寫checkout選中branch的功能,這裡有個小細節請讀者留意,我們需在answer的字串不為空的狀況才執行程式碼。因為Inputbox可能會遇到使用者點到其他vscode ui跳掉,這時根據我們前面的邏輯,answer會自動拿到空值,導致之後的邏輯設成item的文字為空,這時候在使用者看起來就像是item消失一樣。Checkout branch時的處理邏輯如下:

    ...
} else if (answer !=='') {			
    item.text = git.checkout(answer);		
    vscode.window.showInformationMessage(`Checkout to branch ${git.currentBranch}`);
} 

到這裡為止,整個git的處理流程與邏輯均已完成,讓我們執行看看整個操作流程吧!

  1. 創建一個新的Branch,checkout到新的branch,刷新statusBarItem:

  1. Checkout回先前的day10-master branch

隨堂測驗:新增Delete Branch的選項


到這裡為止,我們完成了創建新的branch、切換選擇的branch這兩種功能,現在如果我們要讓使用者可以刪除這個branch,應該要怎麼完成他們呢? 這個問題我們會留給讀者練習並嘗試解答,希望讀者試著自己思考後寫下程式碼後並完成功能喔,答案我們之後會揭曉。

結語:


好的,今天的練習到這裡為止!我們成功模擬了一個使用者互動情境,並取得用戶輸入結果,大家是不是對vscode的核心api越來越有感覺了呢?在今天的練習裡,我們運用到的JS的Class與非同步async/await來處理現實當中extension需求,讀者們的js/ts基礎越穩固,對於這章的理解也會越好。如有問題,請在文章下方留言給我,我會針對您的問題幫忙解惑。

明天,會有更多的介紹,我們明天見,掰掰!

參考文件



上一篇
Day09 | Data Storage以及教學中沒有特別提及的小細節
下一篇
Day11 | 那些跟extension開發脫不了關係的window命名空間api
系列文
自己用的工具自己做! 30天玩轉VS Code Extension之旅36
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言