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
17 changes: 12 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ name: Release
# release with the archives attached (cargo-binstall reads them, see [package.metadata.binstall]).
# To release, bump `version` in Cargo.toml (and the mdown entry in Cargo.lock), commit, then either
# - in the browser: Actions > Release > Run workflow, on main. The release step creates the
# tag v<version> on that commit; or
# tag v<version> on that commit (preferred: nothing appears until the crate is published);
# - in the browser: Releases > Draft a new release, with a new tag v<version> on main. The
# tag starts this workflow, which attaches the archives to that release when it's done; or
# - from a terminal: git tag v<version> && git push origin v<version>
# Don't create the release by hand on GitHub: this workflow makes it once the crate is published.
# Publishing needs a crates.io API token stored as the repository secret CARGO_REGISTRY_TOKEN.

on:
Expand Down Expand Up @@ -110,8 +111,14 @@ jobs:
with:
path: dist
merge-multiple: true
- name: Create the release
- name: Create the release, or add the archives to one made on GitHub
env:
GH_TOKEN: ${{ github.token }}
# On a manual run the tag doesn't exist yet; --target creates it on the commit just built.
run: gh release create "${{ needs.check.outputs.tag }}" dist/* --repo "${{ github.repository }}" --target "${{ github.sha }}" --title "${{ needs.check.outputs.tag }}" --generate-notes
TAG: ${{ needs.check.outputs.tag }}
run: |
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$TAG" dist/* --repo "$GITHUB_REPOSITORY" --clobber
else
# On a manual run the tag doesn't exist yet; --target creates it on the commit just built.
gh release create "$TAG" dist/* --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "$TAG" --generate-notes
fi
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mdown"
version = "0.1.1"
version = "0.2.0"
edition = "2024"
rust-version = "1.90"
description = "A lightweight native Markdown viewer and editor with math, diagrams, charts and 3D models"
Expand Down
6 changes: 4 additions & 2 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ Double-click a `.md` file and it opens in its own small window, fully rendered,
- **Theme (built):** `system` (default, follows the OS), `light` or `dark`. Cycle with Ctrl/Cmd+Shift+L (saved globally and pushed to every open window), set with `mdown theme [system|light|dark]`, or edit `settings.json` (`%APPDATA%\mdown\` on Windows, `~/Library/Application Support/mdown/` on macOS; `{ "theme": "dark" }`). The saved theme is stamped on `<html data-theme>` when the page is served, so there is no flash; the title bar follows via tao's `set_theme`. Mermaid, Chart.js, code highlighting, the editor and the 3D viewer follow it; print is always light.
- **Settings (built):** `settings.json` holds `theme`, `width` (`normal` | `wide`, the reading column) and `zoom` (0.5 to 3.0, in 0.1 steps). Invalid or missing values fall back to defaults and unknown keys survive a save. The page sends one generic IPC message (`{t:"setting", key, value}`); Rust validates and saves it, then evaluates `__applySettings(settings, changedKey)` in every window (the window that asked also shows a toast). Text size is the webview's native zoom (`WebView::zoom`), with wry's built-in hotkey zoom turned off so the page owns the shortcuts. Theme, width and zoom are stamped on `<html>` at serve time.
- **Context menu (built):** a right-click menu drawn in the page (same look on both OSes, no extra crates). Top section depends on the target: Copy / Select all in the preview, plus Copy link address on links and Copy code on code blocks; Cut / Copy / Paste / Select all in the editor. Then Edit mode or View mode, Save (enabled while there are unsaved edits), Print / Save as PDF, flyouts for Theme, Text size and Page width, Show in File Explorer / Reveal in Finder, and Copy file path. Mouse presses on the menu are swallowed so the selection survives; arrow keys, Enter and Escape work. WebView2 needs `with_clipboard(true)` or Paste raises a permission prompt.
- **Shortcuts:** Ctrl/Cmd+E edit, +S save, +P print/PDF, +Shift+L cycle theme, +`+` / +`-` / +0 text size (Ctrl+wheel and trackpad pinch too); Cmd+C/V/X/A/Z/W/Q on macOS come from the menu bar.
- **Reading (built):** Ctrl/Cmd+F opens a find bar over the preview (`frontend/src/find.js`): matches are wrapped in `<mark>` elements, may span inline formatting but not blocks, skip SVG and KaTeX's MathML, and are redone after every re-render. Ctrl/Cmd+Shift+O toggles a per-window *Contents* panel (`outline.js`) that tracks the current section. GitHub alerts (`alerts.js`), click-to-zoom for images shown below their natural size, and dropping `.md` files on a window (wry's native drop handler, which has the real paths) to open them.
- **Source lines (built):** every rendered block carries `data-line`, its 0-based source line. The preview follows the editor by interpolating between the blocks around the editor's top line, and outline clicks in edit mode move the editor.
- **Shortcuts:** Ctrl/Cmd+F find, +Shift+O contents, Ctrl/Cmd+E edit, +S save, +P print/PDF, +Shift+L cycle theme, +`+` / +`-` / +0 text size (Ctrl+wheel and trackpad pinch too); Cmd+C/V/X/A/Z/W/Q on macOS come from the menu bar.
- **Window:** sensible default size, remember last size globally (a small config file), title shows the file name, plus a dirty marker in edit mode.

### Open-file handling
Expand Down Expand Up @@ -126,7 +128,7 @@ crates.io limits a published crate to 10 MB compressed. The embedded frontend (m
- **Icon (built):** `frontend/mkicon.mjs` draws `assets/icon.svg` and writes every format into `assets/`, all committed so a build never needs Node: `icon.ico`, `icon.icns`, `icon.png`, `icon-64.rgba` (window icon) and `mdown.res`, a precompiled Windows resource that `build.rs` links into both exes (MSVC only; no `rc.exe` needed). Windows shows it in the exe, Explorer, the title bar and the registry entries; `mdown install` on macOS writes the `.icns` into `mdown.app` (validated with `iconutil`). The design is a simple placeholder-quality mark and is easy to replace: edit the SVG in `mkicon.mjs` and rerun it.
- **README (built):** `README.md` with light/dark/edit/menu screenshots in `docs/` (captured from `docs/showcase.md` through the WebView2 debug port).
- **Crate metadata (built):** description, MIT license (`LICENSE`), keywords, categories, `rust-version = "1.90"` (set by the macOS-only `muda`), binstall metadata, `.github/workflows/ci.yml` (tests and a release build on Windows and macOS for pushes to `main` and PRs) and `release.yml`. Repository: https://github.com/RAZKOM/mdown.
- **Releasing:** bump `version` in `Cargo.toml` (and the `mdown` entry in `Cargo.lock`, or `cargo publish` refuses the dirty tree), commit, then either run *Actions → Release → Run workflow* on `main` from the browser (the last step creates the tag `v<version>`), or `git tag v<version> && git push origin v<version>`. Don't create the GitHub release by hand: the workflow makes it, and would fail if it already existed. `release.yml` runs `check` (a pushed tag must equal the Cargo.toml version; a manual run must be on `main` and the tag must not exist yet), `build` (Windows x64 and macOS arm64/x64 archives), `publish` (`cargo publish` from a Windows runner, using the repository secret `CARGO_REGISTRY_TOKEN`), then `release` (GitHub release with the archives, which `cargo binstall` downloads). The first publish of a new crate name needs a crates.io API token; trusted publishing can replace the token once the crate exists.
- **Releasing:** bump `version` in `Cargo.toml` (and the `mdown` entry in `Cargo.lock`, or `cargo publish` refuses the dirty tree), commit, then either run *Actions → Release → Run workflow* on `main` from the browser (the last step creates the tag `v<version>`), or `git tag v<version> && git push origin v<version>`. Publishing a release from GitHub's *Releases* page with a new tag also works: the tag starts the workflow, which attaches the archives to that release instead of creating one (v0.1.1 went out this way before that step existed, so its release has no archives and binstall builds it from source). `release.yml` runs `check` (a pushed tag must equal the Cargo.toml version; a manual run must be on `main` and the tag must not exist yet), `build` (Windows x64 and macOS arm64/x64 archives), `publish` (`cargo publish` from a Windows runner, using the repository secret `CARGO_REGISTRY_TOKEN`), then `release` (GitHub release with the archives, which `cargo binstall` downloads). The first publish of a new crate name needs a crates.io API token; trusted publishing can replace the token once the crate exists.
- **Dev hooks:** `MDOWN_DEBUG_JS` and the startup timing marks exist only with `--features debug-hooks`; `window.__editor` / `window.__print` stay in the page as test hooks.
- **Package check:** `cargo publish --dry-run` packages 201 files, 7.6 MiB (2.5 MiB compressed, limit 10 MiB) and builds from the tarball.

Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ mdown notes.md # open a file
mdown a.md b.md c.md # one window each
```

Links between Markdown files open in a new window (`../` links included), links to folders, PDFs, images and text files open in their usual app, and links to anything else are shown in the file manager rather than run. Images and models resolve relative to the document, and the view updates by itself whenever the file changes on disk. If you have unsaved edits when that happens, mdown asks before replacing them.
Drop `.md` files on a window to open them too. Links between Markdown files open in a new window (`../` links included), links to folders, PDFs, images and text files open in their usual app, and links to anything else are shown in the file manager rather than run. Images and models resolve relative to the document, and the view updates by itself whenever the file changes on disk. If you have unsaved edits when that happens, mdown asks before replacing them.

### Open `.md` files from the file manager

Expand All @@ -49,6 +49,8 @@ For scripts: `mdown install --context-menu`, `--default` or `--all`, with `--yes
## What it renders

- **Markdown**: tables, task lists, footnotes, heading anchors, strikethrough, autolinks, front matter (hidden), and inline HTML (sanitized).
- **Alerts**: GitHub's `> [!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]` and `[!CAUTION]` callouts.
- **Images**: click one that's shown smaller than its real size to see it full size.
- **Code**: syntax highlighting for 28 common languages, loaded only when a document uses them.
- **Math**: `$inline$` and `$$display$$` with KaTeX.
- **Diagrams**: ```` ```mermaid ```` fences.
Expand All @@ -57,22 +59,28 @@ For scripts: `mdown install --context-menu`, `--default` or `--all`, with `--yes

A block that fails (bad Mermaid, broken JSON, a missing model) shows an inline error and the rest of the page renders normally. Each of the heavier features is loaded only when the document needs it, so plain Markdown stays quick. See [`docs/showcase.md`](docs/showcase.md) for the document in the screenshots.

## Reading

<kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>F</kbd> finds text in the page (<kbd>Enter</kbd> and <kbd>Shift</kbd>+<kbd>Enter</kbd> step through the matches, <kbd>Esc</kbd> closes). <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd> opens a *Contents* panel listing the headings, with the section you're reading highlighted; click one to jump to it.

## Editing and PDF

<kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>E</kbd> splits the window into an editor and a live preview (a CodeMirror editor with Markdown highlighting, undo history and search); press it again to go back to reading. <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>S</kbd> saves. Closing a window with unsaved edits asks first.
<kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>E</kbd> splits the window into an editor and a live preview (a CodeMirror editor with Markdown highlighting, undo history and search); press it again to go back to reading. The preview follows the editor line by line as you scroll, and clicking a heading in the *Contents* panel moves the editor there. <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>S</kbd> saves. Closing a window with unsaved edits asks first.

<kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>P</kbd> opens the system print dialog, where *Save as PDF* is one of the printers. Printing always uses a clean light layout, with diagrams, charts and 3D models drawn as static images.

## Right-click menu

Right-click anywhere for copy and select-all (cut and paste in the editor), *Copy link address* and *Copy code* on links and code blocks, edit/view mode, save, print, the **theme**, **text size** and **page width** settings, *Show in File Explorer* / *Reveal in Finder*, and *Copy file path*.
Right-click anywhere for copy and select-all (cut and paste in the editor), *Copy link address* and *Copy code* on links and code blocks, *Find*, edit/view mode, save, print, *Contents*, the **theme**, **text size** and **page width** settings, *Show in File Explorer* / *Reveal in Finder*, and *Copy file path*.

<p align="center"><img src="docs/menu.png" width="360" alt="the right-click menu with the Theme submenu open"></p>

## Keyboard shortcuts

| | |
|---|---|
| <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>F</kbd> | Find (in the editor: the editor's search) |
| <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd> | Show or hide the *Contents* panel |
| <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>E</kbd> | Toggle edit mode |
| <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>S</kbd> | Save |
| <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>P</kbd> | Print or save as PDF |
Expand Down
Loading
Loading