✨feature: Make checklist file configurable
This commit is contained in:
15
package.json
15
package.json
@@ -21,6 +21,21 @@
|
|||||||
"title": "Roadmap: Open Tab"
|
"title": "Roadmap: Open Tab"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"configuration": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "Development Checklist.md",
|
||||||
|
"description": "Filename of the markdown checklist to use for the roadmap view.",
|
||||||
|
"scope": "workspace",
|
||||||
|
"properties": {
|
||||||
|
"roadmapChecklist.filename": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Development Checklist.md",
|
||||||
|
"description": "The relative path to the markdown file used for the roadmap checklist."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"activitybar": [
|
"activitybar": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,48 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { RoadmapTreeProvider, RoadmapItem } from './roadmapTree';
|
import { RoadmapTreeProvider, RoadmapItem } from './roadmapTree';
|
||||||
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(this: any, context: vscode.ExtensionContext) {
|
||||||
const checklistFile = path.join(vscode.workspace.workspaceFolders?.[0].uri.fsPath || '', 'Development Checklist.md');
|
const output = vscode.window.createOutputChannel('Roadmap Checklist');
|
||||||
console.log('[Extension] Using checklist path:', checklistFile);
|
const config = vscode.workspace.getConfiguration('roadmapChecklist');
|
||||||
|
const checklistFilename = config.get<string>('filename') || 'Development Checklist.md';
|
||||||
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
|
|
||||||
const roadmapProvider = new RoadmapTreeProvider(checklistFile, context);
|
if (workspaceFolder) {
|
||||||
|
const filePath = path.join(workspaceFolder.uri.fsPath, checklistFilename);
|
||||||
|
this.checklistPath = filePath;
|
||||||
|
|
||||||
|
console.log(`Using checklist file: ${this.checklistPath}`);
|
||||||
|
output.appendLine(`Using checklist file: ${this.checklistPath}`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(this.checklistPath)) {
|
||||||
|
vscode.window.showWarningMessage(`Checklist file not found: ${this.checklistPath}`);
|
||||||
|
} else {
|
||||||
|
output.appendLine('Checklist file found, refreshing...');
|
||||||
|
setTimeout(() => this.refresh(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const configSet = `Roadmap Checklist filename set to: ${checklistFilename}`;
|
||||||
|
output.appendLine(configSet);
|
||||||
|
|
||||||
|
const checklistPath = vscode.workspace.workspaceFolders?.[0]
|
||||||
|
? vscode.Uri.joinPath(vscode.workspace.workspaceFolders[0].uri, checklistFilename).fsPath
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const message = `Using checklist file: ${this.checklistPath}`;
|
||||||
|
console.log(message);
|
||||||
|
output.appendLine(message);
|
||||||
|
output.show(); // Optional, only if you want it to be visible
|
||||||
|
|
||||||
|
// if (fs.existsSync(checklistPath)) {
|
||||||
|
// console.log('[Extension] Roadmap checklist file found:', checklistPath);
|
||||||
|
// } else {
|
||||||
|
// vscode.window.showWarningMessage(`Roadmap checklist file not found: ${checklistPath}`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const roadmapProvider = new RoadmapTreeProvider(checklistPath, context);
|
||||||
vscode.window.registerTreeDataProvider('roadmapChecklist', roadmapProvider);
|
vscode.window.registerTreeDataProvider('roadmapChecklist', roadmapProvider);
|
||||||
const treeView = vscode.window.createTreeView('roadmapChecklist', {
|
const treeView = vscode.window.createTreeView('roadmapChecklist', {
|
||||||
treeDataProvider: roadmapProvider
|
treeDataProvider: roadmapProvider
|
||||||
@@ -14,11 +50,14 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
vscode.commands.registerCommand('roadmap.toggleCheckbox', async (item: RoadmapItem) => {
|
vscode.commands.registerCommand('roadmap.toggleCheckbox', async (item: RoadmapItem) => {
|
||||||
const doc = vscode.workspace.textDocuments.find(d => d.uri.fsPath === checklistFile);
|
const doc = vscode.workspace.textDocuments.find(d => d.uri.fsPath === checklistPath);
|
||||||
if (!doc) { return; }
|
if (!doc) { return; }
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
const lines = doc.getText().split('\n');
|
const rawText = doc.getText();
|
||||||
|
|
||||||
|
// Normalize line endings and split into lines
|
||||||
|
const lines = rawText.split(/\r?\n/);
|
||||||
const index = lines.findIndex(line =>
|
const index = lines.findIndex(line =>
|
||||||
line.trim().match(/^[-*]\s+\[[ xX]\]/) &&
|
line.trim().match(/^[-*]\s+\[[ xX]\]/) &&
|
||||||
line.includes(item.label)
|
line.includes(item.label)
|
||||||
@@ -27,11 +66,20 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
const line = lines[index];
|
const line = lines[index];
|
||||||
const toggledLine = line.replace(/\[(x| )\]/i, item.checked ? '[ ]' : '[x]');
|
const toggledLine = line.replace(/\[(x| )\]/i, item.checked ? '[ ]' : '[x]');
|
||||||
const range = new vscode.Range(new vscode.Position(index, 0), new vscode.Position(index, line.length));
|
lines[index] = toggledLine;
|
||||||
edit.replace(doc.uri, range, toggledLine);
|
|
||||||
|
// Ensure exactly one trailing newline
|
||||||
|
const finalText = lines.join('\n').replace(/\n+$/, '') + '\n';
|
||||||
|
|
||||||
|
const fullRange = new vscode.Range(
|
||||||
|
doc.positionAt(0),
|
||||||
|
doc.positionAt(rawText.length)
|
||||||
|
);
|
||||||
|
|
||||||
|
edit.replace(doc.uri, fullRange, finalText);
|
||||||
|
|
||||||
await vscode.workspace.applyEdit(edit);
|
await vscode.workspace.applyEdit(edit);
|
||||||
await doc.save(); // ✅ Triggers the existing onDidSaveTextDocument → refresh()
|
await doc.save(); // ✅ Triggers refresh via onDidSave
|
||||||
}),
|
}),
|
||||||
vscode.commands.registerCommand('roadmapChecklist.reveal', async (item: RoadmapItem) => {
|
vscode.commands.registerCommand('roadmapChecklist.reveal', async (item: RoadmapItem) => {
|
||||||
treeView.reveal(item, { expand: true });
|
treeView.reveal(item, { expand: true });
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// roadmapTree.ts
|
// roadmapTree.ts
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
export class RoadmapItem extends vscode.TreeItem {
|
export class RoadmapItem extends vscode.TreeItem {
|
||||||
public children: RoadmapItem[] = [];
|
public children: RoadmapItem[] = [];
|
||||||
@@ -60,6 +61,8 @@ export class RoadmapItem extends vscode.TreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RoadmapTreeProvider implements vscode.TreeDataProvider<RoadmapItem> {
|
export class RoadmapTreeProvider implements vscode.TreeDataProvider<RoadmapItem> {
|
||||||
|
private output = vscode.window.createOutputChannel('Roadmap Checklist');
|
||||||
|
|
||||||
private _onDidChangeTreeData: vscode.EventEmitter<RoadmapItem | undefined | void> = new vscode.EventEmitter();
|
private _onDidChangeTreeData: vscode.EventEmitter<RoadmapItem | undefined | void> = new vscode.EventEmitter();
|
||||||
readonly onDidChangeTreeData: vscode.Event<RoadmapItem | undefined | void> = this._onDidChangeTreeData.event;
|
readonly onDidChangeTreeData: vscode.Event<RoadmapItem | undefined | void> = this._onDidChangeTreeData.event;
|
||||||
|
|
||||||
@@ -83,8 +86,20 @@ export class RoadmapTreeProvider implements vscode.TreeDataProvider<RoadmapItem>
|
|||||||
}
|
}
|
||||||
|
|
||||||
refresh(): void {
|
refresh(): void {
|
||||||
|
let content = '';
|
||||||
const doc = vscode.workspace.textDocuments.find(d => d.uri.fsPath === this.checklistPath);
|
const doc = vscode.workspace.textDocuments.find(d => d.uri.fsPath === this.checklistPath);
|
||||||
const content = doc?.getText() || '';
|
|
||||||
|
if (doc) {
|
||||||
|
content = doc.getText();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
content = fs.readFileSync(this.checklistPath, 'utf8');
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showErrorMessage(`Failed to read checklist file: ${err}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const expanded = this.context.workspaceState.get<string[]>('expandedPhases') || [];
|
const expanded = this.context.workspaceState.get<string[]>('expandedPhases') || [];
|
||||||
const { items, firstOpenPhase } = this.parseMarkdown(content, expanded);
|
const { items, firstOpenPhase } = this.parseMarkdown(content, expanded);
|
||||||
this.items = items;
|
this.items = items;
|
||||||
|
|||||||
Reference in New Issue
Block a user