Thực hành: viết extension đầu tiên
← Về MOC · Trước: Built-in Extensions – extension tích hợp sẵn
Nguồn chính thức: Your First Extension và Extension Anatomy trên code.visualstudio.com/api.
Không cần build repo
vscodeViết extension chỉ cần VS Code bản thường + Node.js. Build repo
vscode(Build & Run từ mã nguồn) chỉ cần khi bạn muốn sửa chính VS Code.
1. Ba khái niệm cốt lõi (Extension Anatomy)
| Khái niệm | Giải thích | Ví dụ |
|---|---|---|
| Activation Event (sự kiện kích hoạt) | Sự kiện khiến extension được nạp và chạy activate() | onLanguage:sql, onCommand:..., onStartupFinished |
| Contribution Point (điểm đóng góp) | Khai báo tĩnh trong package.json để mở rộng VS Code | contributes.commands, contributes.menus, contributes.configuration |
| VS Code API | Các hàm JavaScript extension gọi lúc chạy | vscode.commands.registerCommand, vscode.window.showInformationMessage |
Các trường quan trọng trong package.json:
main: file vào (ví dụ./out/extension.js).engines.vscode: phiên bản API tối thiểu, đồng thời quyết định bản@types/vscodedùng được.activationEvents: từ VS Code 1.74.0, lệnh khai báo trongcontributes.commandstự động kích hoạt extension, không cần ghionCommandnữa.contributes: các contribution point.
2. Tạo khung dự án (scaffold)
Yêu cầu: cài Node.js và Git.
# Cách 1: không cần cài Yeoman toàn cục
npx --package yo --package generator-code -- yo code
# Cách 2: cài toàn cục để dùng nhiều lần
npm install --global yo generator-code
yo codeKhi được hỏi, chọn New Extension (TypeScript), đặt tên HelloWorld, identifier helloworld, khởi tạo Git, chọn bundler unbundled, trình quản lý gói npm (theo hướng dẫn chính thức).
Yeoman là gì?
Yeoman (
yo) là công cụ sinh khung dự án (scaffolding tool).generator-codelà “bộ sinh” do đội VS Code cung cấp.
3. Chạy và debug
- Mở
src/extension.ts. - Nhấn F5 (hoặc lệnh Debug: Start Debugging).
- VS Code biên dịch và mở cửa sổ mới tên Extension Development Host (cửa sổ chạy thử extension).
- Trong cửa sổ đó,
Ctrl+Shift+P→ chạy lệnh Hello World → thấy thông báo “Hello World from HelloWorld!”.
Nếu không thấy lệnh: kiểm tra engines.vscode có tương thích với VS Code đang cài không.
Mã mẫu chính thức (dịch chú thích)
// Module 'vscode' chứa Extension API
import * as vscode from 'vscode';
// Gọi khi extension được kích hoạt (lần đầu lệnh được chạy)
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "helloworld-sample" is now active!');
// commandId phải khớp với trường "command" trong package.json
let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => {
vscode.window.showInformationMessage('Hello World!');
});
// Đưa vào subscriptions để VS Code tự dispose khi extension bị tắt
context.subscriptions.push(disposable);
}
// Gọi trước khi extension bị tắt – nhiều extension không cần
export function deactivate() {}Lưu ý context.subscriptions.push(...) – chính là mô hình Disposable mà lõi VS Code dùng.
4. Bài thực hành nâng cao: “SQL Helper” (tự viết)
Mục tiêu: trong file .sql, thêm lệnh đếm số batch (khối lệnh được tách bởi GO) và hiện kết quả trên status bar.
4.1 package.json (phần quan trọng)
{
"name": "sql-helper",
"displayName": "SQL Helper",
"version": "0.0.1",
"engines": { "vscode": "^1.90.0" },
"main": "./out/extension.js",
"activationEvents": ["onLanguage:sql"],
"contributes": {
"commands": [
{ "command": "sqlHelper.countBatches", "title": "SQL Helper: Đếm số batch" }
],
"menus": {
"editor/context": [
{ "command": "sqlHelper.countBatches", "when": "editorLangId == sql", "group": "navigation" }
]
},
"configuration": {
"title": "SQL Helper",
"properties": {
"sqlHelper.batchSeparator": {
"type": "string",
"default": "GO",
"description": "Từ khóa tách batch (T-SQL dùng GO)"
}
}
}
}
}activationEvents: ["onLanguage:sql"]: kích hoạt khi mở file có language IDsql(do built-in extensionsqlđăng ký – xem Built-in Extensions – extension tích hợp sẵn).when: "editorLangId == sql": menu chuột phải chỉ hiện trong file SQL – cùng cơ chế context key như trong lõi (Contribution Model & Registry).
4.2 src/extension.ts
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// Mục trên status bar, căn trái
const statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
context.subscriptions.push(statusItem);
// Hàm đếm số batch dựa trên từ khóa tách (mặc định GO)
const countBatches = (doc: vscode.TextDocument): number => {
const sep = vscode.workspace.getConfiguration('sqlHelper').get<string>('batchSeparator', 'GO');
// Dòng chỉ chứa từ khóa tách (không phân biệt hoa thường)
const regex = new RegExp(`^\\s*${sep}\\s*$`, 'gim');
const matches = doc.getText().match(regex);
return (matches?.length ?? 0) + 1;
};
// Cập nhật status bar theo editor đang mở
const refresh = () => {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === 'sql') {
statusItem.text = `$(database) ${countBatches(editor.document)} batch`;
statusItem.show();
} else {
statusItem.hide();
}
};
context.subscriptions.push(
vscode.commands.registerCommand('sqlHelper.countBatches', () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
vscode.window.showInformationMessage(`File có ${countBatches(editor.document)} batch.`);
}),
// Nghe sự kiện: đổi editor, sửa nội dung → cập nhật lại
vscode.window.onDidChangeActiveTextEditor(refresh),
vscode.workspace.onDidChangeTextDocument(e => {
if (e.document === vscode.window.activeTextEditor?.document) {
refresh();
}
})
);
refresh();
}
export function deactivate() {}Liên hệ với lõi VS Code
$(database)là cú pháp chèn codicon (bộ icon của VS Code) vào chuỗi.- Khi bạn gán
statusItem.text, phía extension host gọi RPC$setEntrysang workbench – đúng luồng đã phân tích ở Extension Host & RPC.onDidChange…trả vềDisposable– mô hình Event.
4.3 Thử nghiệm
- F5 → mở một file
.sqltrong Extension Development Host:
-- Tạo bảng tạm danh mục tài khoản
CREATE TABLE #DM_TK (TK NVARCHAR(20), TEN_TK NVARCHAR(200));
GO
-- Thêm dữ liệu mẫu
INSERT INTO #DM_TK VALUES (N'111', N'Tiền mặt'), (N'112', N'Tiền gửi ngân hàng');
GO
SELECT * FROM #DM_TK;- Status bar hiện
3 batch. Chuột phải → SQL Helper: Đếm số batch. - Vào Settings, đổi
sqlHelper.batchSeparatorthành;để thử với PostgreSQL (lưu ý: đây chỉ là bài tập; regex hiện tại yêu cầu từ khóa nằm một mình trên dòng).
5. Bước tiếp theo
- Đóng gói
.vsix: công cụ@vscode/vsce(tài liệu Publishing Extensions). - Ví dụ chính thức: repo
microsoft/vscode-extension-samples. - Muốn đóng góp API mới cho VS Code: Quy trình đóng góp (Issue, PR, API).