Add title and context menu for frontmatter in markdown preview

Follow up on #316140

Makes it easier to discover what the table is and hide it
This commit is contained in:
Matt Bierner
2026-05-13 13:43:05 -07:00
parent b64b5fc20f
commit 268eaf471d
6 changed files with 38 additions and 5 deletions
@@ -135,6 +135,11 @@
"title": "%markdown.openImage.title%",
"category": "Markdown"
},
{
"command": "_markdown.openFrontMatterSettings",
"title": "%markdown.openFrontMatterSettings.title%",
"category": "Markdown"
},
{
"command": "markdown.showPreview",
"title": "%markdown.preview.title%",
@@ -221,6 +226,10 @@
{
"command": "_markdown.openImage",
"when": "(webviewId == 'markdown.preview' || webviewId == 'vscode.markdown.preview.editor') && webviewSection == 'localImage'"
},
{
"command": "_markdown.openFrontMatterSettings",
"when": "(webviewId == 'markdown.preview' || webviewId == 'vscode.markdown.preview.editor') && webviewSection == 'frontMatter'"
}
],
"editor/title": [
@@ -7,6 +7,7 @@
"configuration.advanced": "Advanced",
"markdown.copyImage.title": "Copy Image",
"markdown.openImage.title": "Open Image",
"markdown.openFrontMatterSettings.title": "Configure Front Matter Visibility",
"markdown.preview.breaks.desc": "Sets how line-breaks are rendered in the Markdown preview. Setting it to `true` creates a `<br>` for newlines inside paragraphs.",
"markdown.preview.linkify": "Convert URL-like text to links in the Markdown preview.",
"markdown.preview.typographer": "Enable some language-neutral replacement and quotes beautification in the Markdown preview.",
@@ -20,6 +20,7 @@ import { ShowPreviewSecuritySelectorCommand } from './showPreviewSecuritySelecto
import { ShowSourceCommand } from './showSource';
import { ToggleLockCommand } from './toggleLock';
import { OpenImageCommand } from './openImage';
import { OpenFrontMatterSettingsCommand } from './openFrontMatterSettings';
export function registerMarkdownCommands(
commandManager: CommandManager,
@@ -32,6 +33,7 @@ export function registerMarkdownCommands(
commandManager.register(new OpenImageCommand(previewManager));
commandManager.register(new CopyImageCommand(previewManager));
commandManager.register(new OpenFrontMatterSettingsCommand());
commandManager.register(new ShowPreviewCommand(previewManager, telemetryReporter));
commandManager.register(new ShowPreviewToSideCommand(previewManager, telemetryReporter));
commandManager.register(new ShowLockedPreviewToSideCommand(previewManager, telemetryReporter));
@@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { Command } from '../commandManager';
export class OpenFrontMatterSettingsCommand implements Command {
public readonly id = '_markdown.openFrontMatterSettings';
public async execute() {
await vscode.commands.executeCommand('workbench.action.openSettings', '@id:markdown.preview.frontMatter');
}
}
@@ -13,6 +13,7 @@ export type FrontMatterRenderStyle = 'hide' | 'codeBlock' | 'table';
const FRONT_MATTER_TOKEN = 'front_matter';
const MARKER = '---';
const FRONT_MATTER_CONTEXT = JSON.stringify({ webviewSection: 'frontMatter' });
interface IFrontMatterMeta {
readonly content: string;
@@ -131,10 +132,10 @@ function renderAsCodeBlock(meta: IFrontMatterMeta, options: MarkdownIt.Options):
}
}
if (highlighted?.startsWith('<pre')) {
return highlighted + '\n';
return highlighted.replace(/^<pre\b/, `<pre ${frontMatterAttributes()}`) + '\n';
}
const body = highlighted ?? escapeHtml(meta.content);
return `<pre class="frontmatter hljs"><code class="language-yaml">${body}</code></pre>\n`;
return `<pre class="frontmatter hljs" ${frontMatterAttributes()}><code class="language-yaml">${body}</code></pre>\n`;
}
function renderAsTable(meta: IFrontMatterMeta): string {
@@ -148,12 +149,17 @@ function renderAsTable(meta: IFrontMatterMeta): string {
const rows = result.entries.map(([key, value]) =>
`<tr><th>${escapeHtml(key)}</th><td>${formatValueHtml(value)}</td></tr>`
).join('');
return `<table class="frontmatter"><tbody>${rows}</tbody></table>\n`;
return `<table class="frontmatter" ${frontMatterAttributes()}><tbody>${rows}</tbody></table>\n`;
}
function renderError(message: string): string {
const label = vscode.l10n.t('Failed to parse front matter');
return `<div class="frontmatter-error" role="alert"><strong>${escapeHtml(label)}</strong><pre>${escapeHtml(message)}</pre></div>\n`;
return `<div class="frontmatter-error" role="alert" ${frontMatterAttributes()}><strong>${escapeHtml(label)}</strong><pre>${escapeHtml(message)}</pre></div>\n`;
}
function frontMatterAttributes(): string {
const label = escapeHtml(vscode.l10n.t('Frontmatter'));
return `title="${label}" data-vscode-context='${escapeHtml(FRONT_MATTER_CONTEXT)}'`;
}
interface IParseResult {
@@ -91,7 +91,7 @@ suite('markdown.engine', () => {
const engine = createNewMarkdownEngine();
assert.strictEqual(
(await engine.render(input)).html,
'<table class="frontmatter"><tbody><tr><th>title</th><td>Hello</td></tr></tbody></table>\n'
'<table class="frontmatter" title="Frontmatter" data-vscode-context=\'{&quot;webviewSection&quot;:&quot;frontMatter&quot;}\'><tbody><tr><th>title</th><td>Hello</td></tr></tbody></table>\n'
+ '<h1 data-line="4" class="code-line" dir="auto" id="world">World</h1>\n'
);
});