Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
"dist/**",
"node_modules/**",
"out/**",
"test/fixtures/**",
],
}
19 changes: 18 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
"tasks": [
{
"label": "watch",
"dependsOn": ["pnpm: watch:node", "pnpm: watch:tsc", "pnpm: watch:web"],
"dependsOn": [
"pnpm: watch:node",
"pnpm: watch:preview",
"pnpm: watch:tsc",
"pnpm: watch:web"
],
"presentation": {
"reveal": "never"
},
Expand All @@ -14,6 +19,18 @@
"isDefault": true
}
},
{
"type": "shell",
"command": "pnpm run watch:preview",
"group": "build",
"problemMatcher": "$esbuild-watch",
"isBackground": true,
"label": "pnpm: watch:preview",
"presentation": {
"group": "watch",
"reveal": "never"
}
},
{
"type": "shell",
"command": "pnpm run watch:node",
Expand Down
3 changes: 3 additions & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.vscode-test/**
artifacts/**
docs/**
media/**
out/**
node_modules/**
scripts/**
Expand All @@ -23,7 +24,9 @@ pnpm-lock.yaml
pnpm-workspace.yaml
vsc-extension-quickstart.md
**/tsconfig.json
**/tsconfig.*.json
**/eslint.config.mjs
**/vitest.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Better Markdown Preview extends VS Code's built-in Markdown preview. Read
## Project Map

- `src/extension.ts`: shared, browser-safe extension lifecycle entry point.
- `src/markdown/`: Markdown-It composition and focused parser tests.
- `src/preview/`: idempotent browser runtime, local Mermaid adapter, and DOM
lifecycle tests.
- `media/preview.css`: source for the theme-aware contributed preview style.
- `src/test/`: tests executed in a real VS Code Extension Host.
- `test/`: fast manifest and packaged-artifact contract tests.
- `scripts/`: small cross-platform harness helpers.
Expand All @@ -32,6 +36,30 @@ Better Markdown Preview extends VS Code's built-in Markdown preview. Read
- `.vscode-test/` contains a complete downloaded VS Code distribution, including
its own tool configs. Keep it excluded from repository-wide format and lint
discovery.
- Native preview typography uses `--markdown-font-size` and
`--markdown-line-height` (without a `--vscode-` prefix). VS Code 1.125 injects
Markdown alert IDs as custom properties such as
`--vscode-markdownAlert-note.foreground`; escape the dot in CSS and retain
the normalized hyphen form as a compatibility fallback.
- Airplan column closing delimiters allow trailing horizontal whitespace;
container-looking lines inside backtick or tilde fences are code, not nested
column syntax.
- VS Code 1.125 configures its supplied Markdown-It's linkifier with
`fuzzyLink: false` and reapplies per-render options after contributed plugins.
The extension's narrow post-native pass must therefore fill missing GFM HTTP,
HTTPS, email, and `www.` literals without mutating `md.options.linkify`.
- VS Code 1.125 collapses backslash-escaped punctuation into plain inline text
before contributed core rules run. When the resulting token is identical to
authored text (for example `www\.example.com` versus `www.example.com`), do
not guess at raw-source offsets in a core rule; preserve source maps and record
the native-host limitation instead.
- VS Code's source-map core rule adds `data-line`, `code-line`, and `dir` attrs
to mapped non-inline tokens before rendering. Owned block renderers must emit
`renderer.renderAttrs(token)` on the real wrapper; `html_block` attrs otherwise
land on a separate empty mapping element.
- Same-document preview edits can reuse Mermaid `<pre>` nodes, while a preview
retarget replaces `.markdown-body` itself. DOM lifecycle code must handle both
shapes without retaining stale source or TOC state.
- Use `mise run check` during implementation and `mise run verify` on the
intended final head. Run focused tasks while iterating.

Expand All @@ -50,6 +78,10 @@ VSCE normalizes packaged README and changelog paths to lowercase and renames the
license to `LICENSE.txt`. Package-content assertions should target the archive's
normalized names, not the source filenames.

VSCE accepts only `ui` and `workspace` in `extensionKind`. Web-host eligibility
comes from the manifest's `browser` entry point; do not add a synthetic `web`
extension kind.

GitHub Actions must declare restricted permissions and pin every action to a
full commit SHA. `mise run ci:workflows` enforces syntax, security posture, and
pin freshness.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ All notable changes to Better Markdown Preview will be documented here.

- Scaffold the behavior-free desktop and web extension foundation.
- Add the repository validation, test, packaging, and CI harness.
- Enhance the built-in Markdown preview with GFM, alerts, footnotes, definition
lists, TOML frontmatter, responsive columns, and local Mermaid diagrams.
- Add a theme-aware document layout, responsive table of contents, and rich
native-highlighted code-fence presentation.
- Support the desktop Extension Host and a browser-compatible web bundle with
focused parser, DOM lifecycle, Extension Host, and packaged-artifact
validation.
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
# Better Markdown Preview

Better Markdown Preview will enhance Visual Studio Code's built-in Markdown
preview while preserving its theme, security, resource resolution, and editor
synchronization behavior.
Better Markdown Preview enhances Visual Studio Code's built-in Markdown preview
without replacing it. Native source synchronization, resource resolution,
security settings, code-copy controls, syntax highlighting, and user preview
styles continue to work.

The repository currently contains the generated extension foundation and its
validation harness. It deliberately contributes no Markdown rendering behavior
yet.
It adds:

- Complete visible GFM behavior, including task lists, literal autolinks, and
tag filtering.
- GitHub alerts, footnotes, definition lists, and collapsed TOML frontmatter.
- Responsive Pandoc-style columns and locally bundled Mermaid diagrams.
- Code-block titles, highlighted lines and words, line numbers, and diff-line
annotations while retaining VS Code's native highlighter.
- A responsive H1-H3 table of contents with active-heading tracking.
- A clean layout driven entirely by the active VS Code theme, including high
contrast and print presentation.

Open a Markdown file and run **Markdown: Open Preview** or **Markdown: Open
Preview to the Side**. The built-in preview is enhanced automatically.

## Extended syntax

TOML frontmatter uses exact `+++` delimiter lines at the start of a document.
Columns use the supported Pandoc fenced-div subset:

```markdown
:::: {.columns}
::: {.column width=40%}
Left column
:::
::: {.column}
Right column
:::
::::
```

Rich code metadata follows the language identifier:

````markdown
```ts title="src/example.ts" {1,3-5} /needle/ showLineNumbers
const needle = true; // [!code ++]
```
````

Only an exact lowercase `mermaid` fence renders as a diagram. Mermaid is loaded
from the extension package only when the document contains such a block; source
remains visible if loading or rendering fails.

## Development

Expand All @@ -22,7 +62,8 @@ mise run verify
Use `mise tasks` to discover the complete task surface. The most common loops
are:

- `mise run dev` watches the desktop and web bundles.
- `mise run dev` watches the desktop, web, preview runtime, Mermaid, CSS, and
TypeScript targets.
- `mise run check` runs the fast formatter, linter, type, and unit gate.
- `mise run test:extension` exercises activation in a real Extension Host.
- `mise run package:validate` builds and inspects the VSIX.
Expand Down
53 changes: 49 additions & 4 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,58 @@ the supported Markdown extension contribution points. It does not own a custom
webview. This keeps native source synchronization, theme integration, resource
resolution, workspace trust, and user preview styles intact.

The foundation does not declare those contributions yet. `contributes` remains
empty until the rendering implementation lands as an independently reviewed
change.
The manifest declares `markdown.markdownItPlugins`, `markdown.previewStyles`,
and `markdown.previewScripts`. The extension activation export composes narrow
rules onto the Markdown-It instance supplied by VS Code; it does not construct
the native renderer itself.

## Rendering Boundary

`src/markdown/compose.ts` installs standard Markdown-It plugins for task lists,
definition lists, footnotes, and GitHub alerts. Markdown-It's native linkify
rule runs first when enabled. A narrow post-native `linkify-it` pass fills
missing GFM HTTP, HTTPS, email, and `www.` literals independently of that
setting, while filtering bare domains and other schemes and retaining native
normalization, validation, nesting, and HTML-anchor guards.
VS Code 1.125 collapses some backslash-escaped punctuation before contributed
core rules run, so an escaped `www\.` is indistinguishable from authored
`www.` at this boundary. Local rules cover GFM tag filtering, TOML
frontmatter, responsive columns, exact Mermaid fences, and rich fence metadata.

Renderer wrappers retain and invoke the rule already installed on the supplied
Markdown-It instance. In particular, fenced code delegates to VS Code's native
renderer after recognized metadata and diff annotations are removed. This keeps
Highlight.js, language classes, source maps, and native copy controls
authoritative.

All emitted classes and data attributes are scoped with
`better-markdown-preview` or `bmp`. Invalid extension syntax falls back to
ordinary Markdown rather than partially transforming a document.

## Preview Boundary

`src/preview/runtime.ts` owns idempotent DOM enhancement. It wraps the existing
`.markdown-body` in a layout without replacing that element, preserves heading
and `data-line` nodes, rebuilds the TOC after content replacement or body
retargeting, and augments rich code blocks while retaining their authored text.

`media/preview.css` uses VS Code webview color variables and body theme classes;
it does not own a light or dark palette. VS Code loads user `markdown.styles`
after contributed styles, so user overrides retain precedence.

Mermaid is absent from both Extension Host bundles. The small preview runtime
dynamically imports `dist/preview/mermaid-runtime.js` only after finding an
exact Mermaid block. The renderer uses strict security, derives colors from
VS Code variables, and restores escaped source on every failure path.

## Runtime Boundary

`src/extension.ts` is the shared lifecycle entry point. Esbuild emits it twice:

- `dist/node/extension.js` targets the desktop Extension Host.
- `dist/web/extension.js` targets browser Extension Hosts such as vscode.dev.
- `dist/web/extension.js` is browser-compatible for eligible web Extension
Hosts; the current harness provides structural build evidence rather than an
executed vscode.dev host.

Code reachable from the shared entry point must avoid Node-only APIs. If a
future feature genuinely needs platform-specific code, split the entry points
Expand All @@ -35,3 +77,6 @@ extensions and user styles can coexist.
The accepted bootstrap scope is recorded in
`docs/plans/001-bootstrap-foundation.md`. Plans document intent; source, tests,
and shipped artifacts describe the current implementation.

The rendering contract is recorded in
`docs/plans/002-renderer-implementation.md`.
Loading
Loading