Skip to content

Live HTML preview for docx and slides (--watch), and VS Code live preview - #176

Merged
markbac merged 6 commits into
mainfrom
feature/watch-preview-html-twin
Oct 21, 2026
Merged

markbac merged 6 commits into
mainfrom
feature/watch-preview-html-twin

Conversation

@markbac

@markbac markbac commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a live preview to py-doc docx and py-doc slides and lets the VS Code extension drive it. It also fixes the issues found when reviewing the extension, and formats the Python code with ruff format.

docx / slides --watch

  • Builds the .docx/.pptx on every save, plus an HTML twin served on 127.0.0.1 that reloads itself (the same loop as poster --watch, now watch.py).
  • Twins are written to .py-doc/preview/ and named by their relative path, so no user file is overwritten and two files with the same name in different folders both show.
  • If Word or PowerPoint has the file open, it's skipped with a warning and the preview still updates (OutputLocked).
  • preview.css is used only by the twin and shows page breaks, speaker notes and columns. The twin of a deck shows each slide as a numbered 16:9 box, split where PowerPoint splits it (slides-preview.lua).
  • --port / --no-open without --watch print a warning.

VS Code extension

  • One format detection for the instant preview and the 👁️ button, based on front matter and deck-only blocks. File names no longer decide; real posters (paper, byline, orientation) were being sent to py-doc docx.
  • The live preview runs py-doc as a child process. py-doc picks a free port and the extension reads the address from its serving line. Output goes to an output channel, failures are reported, and stopping ends the whole process tree. New pydoc.executable setting.
  • Front matter is read with js-yaml, so lists such as author: no longer crash the preview.
  • Fixes:
    • The poster and slide headers kept turning into a document header when callouts or captions rendered nested Markdown.
    • Heading accents now apply only on posters and keep code, bold and links.
    • split_level is honoured in the instant preview.
    • Colours and weights are sanitised.
  • Packaging: split into src/ modules, with ESLint and node --test. Added license, icon and repository fields; the .vsix packages with only its runtime dependency.

Shared preview cases

tests/fixtures/preview/cases.json runs through both the instant preview (test/cases.test.js) and the HTML twin (tests/test_preview_cases.py), so the two previews can't drift apart.

Formatting

ruff format with line-length = 120, the width the code was already written to. examples/ and tests/fixtures/ are excluded because example files are included in documents and posters, wrapped to fit. CI now checks it. The formatting commit is listed in .git-blame-ignore-revs. It touches about 100 files, so reviewing commit by commit is easiest (the formatting commit is layout only).

Docs

README, guide (live preview, VS Code), architecture (live previews section, AD-08), workspace.dsl (VS Code extension container, Live preview component, LivePreview dynamic view), requirements FR-161/FR-162 with traceability, and the extension README (install, settings, tests).

Testing

  • pytest: 1363 passed, 11 skipped (Windows, pandoc on the host)
  • ruff check . and ruff format --check . pass
  • Extension: npm run lint and npm test pass (10 tests, including the live preview against a fake py-doc)
  • vsce package builds the .vsix (59 files, 308 KB)
  • py-doc lint docs --strict: 0 warnings

Not tested: the extension inside a real VS Code window, and workspace.dsl against structurizr-cli (no Docker here). Before merging, it's worth running py-doc c4 check docs/architecture/workspace.dsl and trying the 👁️ button once.

🤖 Generated with Claude Code

markbac and others added 6 commits October 21, 2026 14:31
VS Code extension:
- One format detection (front matter and deck-only blocks) for the instant
  preview and the eye button; real posters (paper, byline, orientation) are
  no longer sent to `py-doc docx`, and file names no longer decide
- The front matter header keeps its mode when callouts or captions render
  nested Markdown
- List and mapping values in front matter are shown instead of crashing
- Heading accents only on posters, splitting inline tokens so code, bold
  and links keep their formatting
- A new live preview stops the running one first, waits for the server
  before opening Simple Browser, and the port is a setting
- Slide grouping honours split_level; colours and weights are sanitised;
  command titles no longer repeat "py-doc"

docx/slides --watch:
- HTML twins go to .py-doc/preview, keyed by relative path, so no user
  file is overwritten and same-named files stay apart
- OutputLocked replaces matching "locked" in the message
- convert_file and convert_twin share one render helper
- Twin-only preview.css (page breaks, notes, columns); html.css is
  unchanged for normal HTML builds; page breaks carry a class
- --port/--no-open without --watch warn; served paths are URL-decoded

Docs: README, guide (single files, writing), architecture (live previews,
AD-08), workspace.dsl (VS Code extension, Live preview component and
dynamic view), requirements FR-161/162 with traceability. CI runs the
extension tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le split

- The VS Code extension runs py-doc --watch as a child process instead of in
  a terminal. py-doc picks a free port and the extension reads the address
  from its "serving" line, so windows never fight over a port. Output goes
  to an output channel, failures are reported, and stopping ends the whole
  process tree. New pydoc.executable setting; pydoc.watch.port defaults to 0.
- The HTML twin of a deck shows each slide as a numbered 16:9 box, split
  where PowerPoint splits it (slides-preview.lua, split level and breaks).
- Shared preview cases (tests/fixtures/preview/cases.json) run through both
  the instant preview and the HTML twin, so the two cannot drift apart.
- Front matter is read with js-yaml (core schema) instead of a hand parser.
- extension.js is split into src/ modules (plugin, detect, frontmatter, text,
  watch), with ESLint, node --test and tests for the live preview.
- Ready to package: license, icon, repository, bugs and homepage fields; the
  .vsix keeps js-yaml and leaves out dev dependencies. Install docs added.
- poster_watch.py is now watch.py, as it serves docx and slides too.
- CI lints the extension; docs, model and traceability updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
line-length = 120, the width the code was already written to, so the
reformat changes layout only. examples/ and tests/fixtures/ are left out:
example files are included into documents and posters, wrapped to fit.
CI's lint job now runs `ruff format --check .`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vale 3.24 in CI counts FR-161, FR-162 and the AD-08 context over 30 words;
the near-limit sentences of the live preview docs are split as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@markbac
markbac merged commit 8dae833 into main Oct 21, 2026
7 of 14 checks passed
@markbac
markbac deleted the feature/watch-preview-html-twin branch October 21, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant