✨feature: First working version
This commit is contained in:
@@ -1,26 +1,17 @@
|
||||
// The module 'vscode' contains the VS Code extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
import * as vscode from 'vscode';
|
||||
import { RoadmapTreeProvider } from './roadmapTree';
|
||||
import * as path from 'path';
|
||||
|
||||
// This method is called when your extension is activated
|
||||
// Your extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const checklistFile = path.join(vscode.workspace.workspaceFolders?.[0].uri.fsPath || '', 'Development Checklist.md');
|
||||
console.log('[Extension] Using checklist path:', checklistFile);
|
||||
|
||||
// Use the console to output diagnostic information (console.log) and errors (console.error)
|
||||
// This line of code will only be executed once when your extension is activated
|
||||
console.log('Congratulations, your extension "vscode-project-roadmap" is now active!');
|
||||
const roadmapProvider = new RoadmapTreeProvider(checklistFile);
|
||||
vscode.window.registerTreeDataProvider('roadmapChecklist', roadmapProvider);
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
const disposable = vscode.commands.registerCommand('vscode-project-roadmap.helloWorld', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage('Hello World from VSCode Project Roadmap!');
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('roadmapView.refresh', () => roadmapProvider.refresh())
|
||||
);
|
||||
}
|
||||
|
||||
// This method is called when your extension is deactivated
|
||||
export function deactivate() {}
|
||||
|
||||
73
src/roadmapTree.ts
Normal file
73
src/roadmapTree.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class RoadmapItem extends vscode.TreeItem {
|
||||
constructor(
|
||||
public readonly label: string,
|
||||
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
|
||||
public readonly checked: boolean = false,
|
||||
public readonly children: RoadmapItem[] = []
|
||||
) {
|
||||
super(label, collapsibleState);
|
||||
this.description = checked ? '✅ Done' : '';
|
||||
this.iconPath = new vscode.ThemeIcon(checked ? 'check' : 'circle-large-outline');
|
||||
}
|
||||
}
|
||||
|
||||
export class RoadmapTreeProvider implements vscode.TreeDataProvider<RoadmapItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<RoadmapItem | undefined | void> = new vscode.EventEmitter();
|
||||
readonly onDidChangeTreeData: vscode.Event<RoadmapItem | undefined | void> = this._onDidChangeTreeData.event;
|
||||
|
||||
private items: RoadmapItem[] = [];
|
||||
|
||||
constructor(private readonly checklistPath: string) {
|
||||
this.refresh(); // Load initial data
|
||||
vscode.workspace.onDidSaveTextDocument(doc => {
|
||||
if (doc.uri.fsPath === checklistPath) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
console.log('[Roadmap] Refresh called');
|
||||
const doc = vscode.workspace.textDocuments.find(d => d.uri.fsPath === this.checklistPath);
|
||||
if (!doc) {
|
||||
console.warn(`[Roadmap] Document not open: ${this.checklistPath}`);
|
||||
}
|
||||
|
||||
const content = doc?.getText() || '';
|
||||
console.log('[Roadmap] Loaded content:', content.slice(0, 200)); // preview first 200 chars
|
||||
this.items = this.parseMarkdown(content);
|
||||
this._onDidChangeTreeData.fire();
|
||||
}
|
||||
|
||||
getTreeItem(element: RoadmapItem): vscode.TreeItem {
|
||||
return element;
|
||||
}
|
||||
|
||||
getChildren(element?: RoadmapItem): vscode.ProviderResult<RoadmapItem[]> {
|
||||
return element ? element.children : this.items;
|
||||
}
|
||||
|
||||
private parseMarkdown(content: string): RoadmapItem[] {
|
||||
const lines = content.split('\n');
|
||||
const items: RoadmapItem[] = [];
|
||||
let currentPhase: RoadmapItem | null = null;
|
||||
|
||||
for (const line of lines) {
|
||||
const phaseMatch = line.match(/^##\s+(.+)/);
|
||||
const taskMatch = line.match(/^[-*]\s+\[( |x)\]\s+(.+)/);
|
||||
|
||||
if (phaseMatch) {
|
||||
currentPhase = new RoadmapItem(phaseMatch[1].trim(), vscode.TreeItemCollapsibleState.Collapsed);
|
||||
items.push(currentPhase);
|
||||
} else if (taskMatch && currentPhase) {
|
||||
const checked = taskMatch[1] === 'x';
|
||||
const task = new RoadmapItem(taskMatch[2].trim(), vscode.TreeItemCollapsibleState.None, checked);
|
||||
currentPhase.children.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user