From 2f3b15cd69fdedbcb2ece559d283610f63ef4992 Mon Sep 17 00:00:00 2001 From: Karol Krzosa Date: Mon, 16 Feb 2026 17:34:34 +0100 Subject: [PATCH] Add welcome page showing README.md on first install --- package.json | 4 + src/extension.ts | 198 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 201 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 582db77..fc372d1 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,10 @@ { "command": "vsctags.showLog", "title": "vsctags: Show Log" + }, + { + "command": "vsctags.showWelcome", + "title": "vsctags: Welcome" } ] }, diff --git a/src/extension.ts b/src/extension.ts index 2562069..99db256 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import * as path from "path"; -import { createReadStream } from "fs"; +import { createReadStream, readFileSync } from "fs"; import * as readline from "readline"; // ---- Output Channel for observability ---- @@ -727,9 +727,205 @@ export function activate(context: vscode.ExtensionContext) { }), ); + // Welcome page command + context.subscriptions.push( + vscode.commands.registerCommand("vsctags.showWelcome", () => { + showWelcomePage(context); + }), + ); + + // Auto-show welcome page on first install + const hasShownWelcome = context.globalState.get("vsctags.welcomeShown"); + if (!hasShownWelcome) { + showWelcomePage(context); + context.globalState.update("vsctags.welcomeShown", true); + } + logInfo("Extension activated."); } +// ---- Welcome Page ---- + +function showWelcomePage(context: vscode.ExtensionContext) { + const panel = vscode.window.createWebviewPanel( + "vsctags.welcome", + "vsctags — Welcome", + vscode.ViewColumn.One, + { enableScripts: false }, + ); + + let markdown = ""; + try { + const readmePath = path.join(context.extensionPath, "README.md"); + markdown = readFileSync(readmePath, "utf-8"); + } catch { + markdown = "# vsctags\n\nREADME.md not found."; + } + + panel.webview.html = renderMarkdownHtml(markdown); +} + +/** Minimal Markdown to HTML renderer — no dependencies */ +function renderMarkdownHtml(md: string): string { + let html = escapeHtml(md); + + // Code blocks (``` ... ```) + html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, lang, code) => { + return `
${code.trim()}
`; + }); + + // Inline code + html = html.replace(/`([^`]+)`/g, "$1"); + + // Tables + html = html.replace(/((?:^\|.+\|\s*$\n?)+)/gm, (_m, table: string) => { + const rows = table.trim().split("\n").filter(r => r.trim().length > 0); + if (rows.length < 2) { return table; } + + // Check if second row is separator (|---|---|) + const isSep = /^\|[\s\-:|]+\|$/.test(rows[1].trim()); + if (!isSep) { return table; } + + const parseRow = (row: string) => + row.split("|").slice(1, -1).map(c => c.trim()); + + const headerCells = parseRow(rows[0]); + const thead = "" + headerCells.map(c => `${c}`).join("") + ""; + + const bodyRows = rows.slice(2).map(row => { + const cells = parseRow(row); + return "" + cells.map(c => `${c}`).join("") + ""; + }).join("\n"); + + return `${thead}${bodyRows}
`; + }); + + // Headers + html = html.replace(/^######\s+(.+)$/gm, "
$1
"); + html = html.replace(/^#####\s+(.+)$/gm, "
$1
"); + html = html.replace(/^####\s+(.+)$/gm, "

$1

"); + html = html.replace(/^###\s+(.+)$/gm, "

$1

"); + html = html.replace(/^##\s+(.+)$/gm, "

$1

"); + html = html.replace(/^#\s+(.+)$/gm, "

$1

"); + + // Bold + italic + html = html.replace(/\*\*\*(.+?)\*\*\*/g, "$1"); + html = html.replace(/\*\*(.+?)\*\*/g, "$1"); + html = html.replace(/\*(.+?)\*/g, "$1"); + + // Links + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + + // Unordered lists + html = html.replace(/((?:^- .+$\n?)+)/gm, (_m, block: string) => { + const items = block.trim().split("\n").map(l => `
  • ${l.replace(/^- /, "")}
  • `); + return ``; + }); + + // Ordered lists + html = html.replace(/((?:^\d+\.\s.+$\n?)+)/gm, (_m, block: string) => { + const items = block.trim().split("\n").map(l => `
  • ${l.replace(/^\d+\.\s/, "")}
  • `); + return `
      ${items.join("\n")}
    `; + }); + + // Horizontal rules + html = html.replace(/^---$/gm, "
    "); + + // Paragraphs — wrap remaining loose lines + html = html.replace(/^(?!<[a-z])(\S.+)$/gm, "

    $1

    "); + + // Clean up empty lines + html = html.replace(/\n{3,}/g, "\n\n"); + + return ` + + + + + + + +${html} + +`; +} + +function escapeHtml(text: string): string { + return text + .replace(/&/g, "&") + .replace(//g, ">"); +} + export function deactivate() { logInfo("Extension deactivated."); }