123 lines
2.7 KiB
TypeScript
123 lines
2.7 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as vscode from 'vscode';
|
|
|
|
export function openChangelog(context: vscode.ExtensionContext) {
|
|
const panel = vscode.window.createWebviewPanel(
|
|
'hplToolbox.changelog',
|
|
'HPL Toolbox Changelog',
|
|
vscode.ViewColumn.One,
|
|
{ enableScripts: false }
|
|
);
|
|
const changelogPath = path.join(context.extensionPath, 'CHANGELOG.md');
|
|
let markdown = '# Changelog\n\nCHANGELOG.md was not found.';
|
|
try {
|
|
markdown = fs.readFileSync(changelogPath, 'utf8');
|
|
} catch {
|
|
// Keep the fallback text readable in packaged or development installs.
|
|
}
|
|
panel.webview.html = getHtml(renderMarkdown(markdown));
|
|
}
|
|
|
|
function getHtml(content: string): string {
|
|
return `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<style>
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
padding: 18px;
|
|
font-family: var(--vscode-font-family);
|
|
font-size: var(--vscode-font-size);
|
|
background: var(--vscode-editor-background);
|
|
color: var(--vscode-foreground);
|
|
}
|
|
main {
|
|
max-width: 840px;
|
|
margin: 0 auto;
|
|
}
|
|
h1 {
|
|
margin: 0 0 14px;
|
|
font-size: 20px;
|
|
line-height: 1.25;
|
|
}
|
|
h2 {
|
|
margin: 18px 0 8px;
|
|
padding-top: 12px;
|
|
border-top: 1px solid var(--vscode-panel-border);
|
|
font-size: 15px;
|
|
line-height: 1.3;
|
|
}
|
|
ul {
|
|
margin: 6px 0 12px;
|
|
padding-left: 20px;
|
|
}
|
|
li {
|
|
margin: 4px 0;
|
|
line-height: 1.45;
|
|
}
|
|
p {
|
|
margin: 8px 0;
|
|
line-height: 1.5;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>${content}</main>
|
|
</body>
|
|
</html>`;
|
|
}
|
|
|
|
function renderMarkdown(markdown: string): string {
|
|
const lines = markdown.replace(/\r\n/g, '\n').split('\n');
|
|
const html: string[] = [];
|
|
let inList = false;
|
|
|
|
const closeList = () => {
|
|
if (inList) {
|
|
html.push('</ul>');
|
|
inList = false;
|
|
}
|
|
};
|
|
|
|
for (const rawLine of lines) {
|
|
const line = rawLine.trim();
|
|
if (!line) {
|
|
closeList();
|
|
continue;
|
|
}
|
|
const heading = line.match(/^(#{1,3})\s+(.+)$/);
|
|
if (heading) {
|
|
closeList();
|
|
const level = Math.min(heading[1].length, 2);
|
|
html.push(`<h${level}>${escapeHtml(heading[2])}</h${level}>`);
|
|
continue;
|
|
}
|
|
const listItem = line.match(/^-\s+(.+)$/);
|
|
if (listItem) {
|
|
if (!inList) {
|
|
html.push('<ul>');
|
|
inList = true;
|
|
}
|
|
html.push(`<li>${escapeHtml(listItem[1])}</li>`);
|
|
continue;
|
|
}
|
|
closeList();
|
|
html.push(`<p>${escapeHtml(line)}</p>`);
|
|
}
|
|
closeList();
|
|
return html.join('\n');
|
|
}
|
|
|
|
function escapeHtml(value: string): string {
|
|
return value.replace(/[&<>"']/g, ch => ({
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
}[ch] ?? ch));
|
|
}
|