Skip to content

Minml live preview#7

Merged
phamelink merged 18 commits intomainfrom
minml-live-preview
Mar 27, 2026
Merged

Minml live preview#7
phamelink merged 18 commits intomainfrom
minml-live-preview

Conversation

@phamelink
Copy link
Copy Markdown
Contributor

This PR implements a real-time HTML previewer for MinML, powered by a new Go-based WebAssembly converter and a dedicated VS Code extension. It also streamlines the development and installation process for contributors.

Overview

The goal of this PR is to provide a seamless preview experience for MinML files (.minml, .m) directly within VS Code, ensuring that the rendering is 100% consistent with the Go implementation by using WASM.

Key Features

  • WASM-Powered Conversion: Implemented a Go WASM bridge in go/wasm/main.go that exposes the core MinML-to-HTML conversion logic to the browser environment.
    • VS Code Live Preview Extension: A new extension in devtools/minml-preview that provides a side-by-side live preview panel.
    • Local Asset Support: Implemented a tag strategy in the webview to automatically resolve relative image paths (e.g., img{src=figure.png}[]) against the document's directory, fixing previous "403 Forbidden" errors.
    • Simplified Installation: Added a make vscode-live-preview command to the root Makefile with OS detection (Windows/Linux/macOS) and dependency safeguards for easy local installation.

Technical Details

  • Go: The WASM implementation uses TreeParser and TreeWriter from the minml and html packages to maintain architectural consistency.
  • TypeScript/JS: The extension handles the lifecycle of the WASM instance and ensures the preview updates in real-time as the user types.
  • Infrastructure: Created a root Makefile for various build commands and to handle cross-platform paths for VS Code extensions (~/.vscode/extensions vs %USERPROFILE%.vscode\extensions).

How to Test

  1. Install the extension: make vscode-live-preview
  2. Verify:
    • Restart VS
    • Open any .minml
    • Run the command "MinML: Show Live Preview" from the Command
    • Add an image using img{src=relative/path.png}[] and verify it renders correctly without permission errors.

Files

  • go/wasm/main.go: New WASM entry
  • Makefile: Added vscode-live-preview and OS detection
  • devtools/minml-preview/: Full extension
  • README.md & devtools/README.md: Updated documentation and guides.

Note on Contribution: The initial code for this implementation was developed manually by a human, referencing a cat gif panel view extension.
Generative AI was subsequently used for technical research, troubleshooting specific browser security issues (such as the webview URI transformation), and generating parts of the documentation.

@phamelink phamelink self-assigned this Mar 12, 2026
@phamelink phamelink added the enhancement New feature or request label Mar 12, 2026
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 12, 2026

CLA assistant check
All committers have signed the CLA.

@AntoineBastide47
Copy link
Copy Markdown
Contributor

I get a bunch of errors when I run make build-wasm or open the main.go file in the editor I get a bunch of errors:

Build constraints exclude all the Go files in '/opt/homebrew/opt/go/libexec/src/syscall/js'
Unresolved type 'Value'
Unresolved type 'Value'
Unresolved reference 'String'
Unresolved reference 'ConvertString'
Unresolved reference 'Error'
Unresolved reference 'Global'
Unresolved reference 'Set'
Unresolved reference 'FuncOf'

Are your instructions missing a setup or download step ?

@phamelink
Copy link
Copy Markdown
Contributor Author

Whoops sorry for some reason the file didn't commit. I needed the code from your convert file so I moved it up to make it aceessible. Things should work now. Thanks for the catch!

@AntoineBastide47
Copy link
Copy Markdown
Contributor

AntoineBastide47 commented Mar 12, 2026

I could not run the extension without tinkering with it using codex. Here is what it did:

I made three classes of changes in ~/.vscode/extensions:

  1. I fixed the install layout so VS Code would keep the extension after restart.
     The original make target copied it to ~/.vscode/extensions/minml-preview with no publisher, so VS Code treated it as undefined_publisher.minml-preview-0.0.1 and marked it
     obsolete. I added "publisher": "local", renamed the installed folder to ~/.vscode/extensions/local.minml-preview-0.0.1, and removed the stale undefined_publisher... entry from
     ~/.vscode/extensions/.obsolete.
  2. I fixed the version compatibility so VS Code would load the extension at all.
     Your editor is 1.109.5, but the installed manifest required "vscode": "^1.110.0". I changed that in the installed package.json to "^1.109.0".
  3. I made the command contribution explicit so it shows in the Command Palette.
     In the installed package.json, I added:

  - activationEvents: ["onCommand:minml-preview.showPreview"]
  - contributes.menus.commandPalette: [{ "command": "minml-preview.showPreview" }]
  - a command category of MinML

  The actual extension code in dist/extension.js was already fine. The problems were the install shape, the engine constraint, and the manifest contribution details.

If this is resolved I can start reviewing your PR. Also do you think you can add support for these icons to have it auto enabled:

image

But it does work as expected which means the review should be quick:
image

The setup needs a little rework and then its good.

@phamelink
Copy link
Copy Markdown
Contributor Author

It should be good now, you now have a little button to open the preview to the side or in a full window. Also like I said it is generally good practice to commit the package-lock.json as it freezes the versions of each package used in javascript projects. So it is normal it is there!

@bford
Copy link
Copy Markdown
Contributor

bford commented Mar 20, 2026

Nice work!

General question, which we can discuss further in our meeting today: is this minml previewers completely vscode-specific? How easy or difficult do you expect it would be to port to (extensions to) other IDEs, and how much of the code would be shareable as opposed to vscode-specific?

Minor directory-structure nitpick: I would like everything vscode-specific to be somewhere under an appropriate subdirectory probably named vscode; perhaps that could be at the top level, or perhaps it could be devtools/vscode or maybe more concisely just dev/vscode?

Copy link
Copy Markdown
Contributor

@AntoineBastide47 AntoineBastide47 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM !

@phamelink
Copy link
Copy Markdown
Contributor Author

Nice work!

General question, which we can discuss further in our meeting today: is this minml previewers completely vscode-specific? How easy or difficult do you expect it would be to port to (extensions to) other IDEs, and how much of the code would be shareable as opposed to vscode-specific?

Minor directory-structure nitpick: I would like everything vscode-specific to be somewhere under an appropriate subdirectory probably named vscode; perhaps that could be at the top level, or perhaps it could be devtools/vscode or maybe more concisely just dev/vscode?

I just pushed a new commit with the requested refactoring. And to answer your question, some parts are reusable and some aren't. Basically the web assembly part can be reused everywhere, which means that the logic for converting minml to html comes from the same Go source code, for which we create web assembly and this can be used in any extension. Now to actually have the previewer use this and then display the html as you type in a live fashion will depend on each IDE. I know that for Jetbrains they use Kotlin and Java to make extensions, but other IDEs would work differently. I could also reuse the javascript and HTML used in the vscode extension with minor changes.

So in the end, we already have the HTML which calls for the js file, who in turn loads the wasm module, and converts minml to html correctly. All that remains for each IDE specific extension is to display this in a webview and call a function to update the content after each keyboard action on a file.

But I still went ahead and asked AI to summarise the changes for each of the big IDEs and this is what I got in case your interested:

How Hard Is Each Target IDE?
                                                                                                                                                                                                                    
  JetBrains (IntelliJ, WebStorm, etc.)
  - Hardest port. Java/Kotlin plugin API, no native webview — you'd use JBCefBrowser (Chromium-based), message passing is more complex.                                                                             
  - Reuse: WASM + wasm_exec.js + 90% of main.js. ~225 lines rewritten in Kotlin/Java.                                                                                                                               
                                                                                                                                                                                                                    
  Neovim                                                                                                                                                                                                            
  - Moderate. No native webview — you'd need to spawn a browser process or use a Neovim plugin like peek.nvim as a model (opens a browser window, communicates via WebSocket).
  - Alternatively, output HTML to a temp file and open in browser — much simpler.                                                                                                                                   
  - The WASM renderer could even be replaced with a Node.js/Deno script calling the Go binary directly.
                                                                                                                                                                                                                    
  Zed                                                                                                                                                                                                               
  - Easiest after VS Code. Zed has an extension API with WebView support (using GPUI). Architecture would mirror VS Code's. Message passing and webview lifecycle are similar concepts.                             
                                                                                                                                                                                                                    
  Standalone web app / browser extension                                                                                                                                                                            
  - Trivial. Just host main.js + WASM directly. No extension layer needed — main.js already works in a plain browser if you remove the acquireVsCodeApi() call and wire up your own IPC.                            
                                                                                                                                                                                                                    
  ---
  Summary                                                                                                                                                                                                           
                          
  The architecture is well-suited for porting because:
  1. The heavy lifting (MinML → HTML) lives entirely in main.wasm — zero changes needed                                                                                                                             
  2. The webview UI (main.js) only has 1 IDE-specific line                                                                                                                                                          
  3. The IDE layer is thin (~225 lines) and cleanly separated                                                                                                                                                       
                                                                                                                                                                                                                    
  A port to another IDE means writing ~150–300 lines of IDE-specific glue code and making trivial edits to main.js and the CSS. The renderer itself is untouched.                                                   
              

Copy link
Copy Markdown
Contributor

@bford bford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks!

@phamelink phamelink merged commit 9189147 into main Mar 27, 2026
1 check passed
@phamelink phamelink deleted the minml-live-preview branch March 27, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants