# md-manuscript A small desktop application for Debian that treats a directory of markdown files as an ordered manuscript. * **Left pane** — every `*.md` file in the workspace directory, in a manual order you set by **dragging the `⠿` handle** up and down. * **Right pane** — a markdown text editor for the selected file (optional live preview via the *Preview* checkbox). * **Order + contents are saved and version-controlled with git.** The order lives in `order.json` inside the workspace, so it syncs along with the files. * **Export** the whole manuscript as a single concatenated `.odt` file, with a chapter heading before each file's content. Built in Rust with [`egui`](https://github.com/emilk/egui)/`eframe`. The ODT writer is native (no `pandoc`/LibreOffice needed at runtime). ## Build ```sh cargo build --release # binary: target/release/md-manuscript ``` Requires a Rust toolchain. The GUI needs a normal desktop session (X11 or Wayland) with OpenGL — the usual runtime libraries on Debian: ```sh sudo apt install libgl1 libxkbcommon0 libwayland-client0 libx11-6 ``` (Only needed to *run* the GUI; building does not require them.) ## Install ```sh install -Dm755 target/release/md-manuscript ~/.local/bin/md-manuscript ``` Optionally add a desktop launcher at `~/.local/share/applications/md-manuscript.desktop`: ```ini [Desktop Entry] Type=Application Name=md-manuscript Exec=md-manuscript Categories=Office;TextEditor; Terminal=false ``` ## Use 1. Set the **Workspace** path in the top bar (default: `~/Manuscript`) — type it, or click **📂** to pick a folder in a native file browser — and press **Open**. The directory is created if it does not exist. 2. Press **Init git** once to make the workspace a git repository. To sync with another machine, add a remote yourself: ```sh cd ~/Manuscript git remote add origin git push -u origin main ``` After that, the **⟳ Sync (git)** button commits all changes, `pull --rebase`s, and pushes. If you open a folder that is *not* itself a repository but sits inside one (a parent directory is a git work tree), the app asks whether to **use the enclosing repository**. Accept it to have **⟳ Sync** commit and push to that repo; decline to leave the workspace on its own, where **Init git** creates a separate repository in the folder. 3. Create files with **+ New**, edit on the right, `Ctrl+S` (or the Save button) to write to disk. Drag the `⠿` handles to reorder. Use the **Zoom** slider above the editor to scale the editor text (0% = default; **Reset** returns to it), and the **Contrast** slider to brighten dim editor text (0% = theme default; higher pushes the text toward white in dark mode / black in light mode). Text always wraps to the pane width, so there is no horizontal scrolling. 4. Set the **Chapter title** for the open file if you want to override the auto-derived one (the field shows the automatic title as a hint). Leaving it blank falls back to a `# Title:` line in the header, and if there is none, to the chapter's **position in the left pane** followed by a period (`1.`, `2.`, …). Tick **Zero-pad #** in the top bar to pad those numbered titles with leading zeros to a uniform width (e.g. `03.` when there are 12 chapters). Titles are saved to `titles.json` and sync with git. 5. Set the **Export** path (type it, or click **📂** to choose the `.odt` file in a native save dialog) and press **Export ODT** to produce the concatenated document. Each file becomes a chapter headed by its title, optionally followed by a caption from its `# Slug:` line. **Every chapter starts on a new page** (the first chapter excepted, so there is no blank leading page). The status bar shows a live **word count** for the current file, plus the net words added (or removed) to it since the current session started. The count updates as you type, including unsaved edits. ## Grammar & spelling (LanguageTool) The editor can check the current file against a [LanguageTool](https://languagetool.org/) server — typically a **local instance**, so your manuscript never leaves your machine. 1. Run a LanguageTool server. The standalone server listens on `http://localhost:8010` by default (the official Docker image uses `:8081` — just point the app at whichever you run): ```sh # Standalone (needs Java): java -cp 'languagetool-server.jar' org.languagetool.server.HTTPServer --port 8010 # or via Docker: docker run -d -p 8010:8010 --entrypoint java \ erikvl87/languagetool -cp languagetool-server.jar \ org.languagetool.server.HTTPServer --port 8010 --allow-origin '*' ``` 2. Open **Settings ▸ LanguageTool…** (from the menu bar, or the **⚙** button on the Grammar row) and set the connection: * **Scheme** — `http` for a local server, `https` for a remote one (TLS is supported). * **Host / domain** — an IP address or hostname (default `localhost`). * **Port** — the server's port (default `8010`). * **Token** — optional; sent as an `Authorization: Bearer` header for a server behind an auth proxy, or a premium API key. Leave blank for an unauthenticated local server. * **Language** — `auto` to detect, or a code like `en-US`, `en-GB`, `de-DE`. Press **Test connection** to confirm the settings reach a working server. All fields are remembered in the config. 3. Open a file and press **✓ Check**. The check runs in the background (the UI stays responsive) and issues appear two ways: * **Underlines in the editor** — red for spelling, blue for grammar/style. * **A "Grammar & spelling" panel** at the bottom listing each issue with its explanation and suggested fixes. Click a suggestion to apply it; the remaining underlines re-align automatically. Editing the text after a check hides the underlines (their positions would no longer be accurate) and disables the fix buttons until you re-check. The checker sends the raw file text, so occasional markdown tokens (e.g. a `#` heading marker) may be flagged. ## Header stripping on export Manuscript files often carry editorial notes and metadata above the prose that should not appear in the finished document. On export, each file is cleaned up: * **HTML comments** (``, including multi-line ones) are removed. * **The header block** — everything above the **Draft marker** line (set in the top bar; default `### Rough Draft:`) — is dropped. From that header: * `# Title:` becomes the chapter heading (unless a manual override is set), and * `# Slug:` becomes an italic caption printed beneath the heading. Any other header text is discarded. Files with no marker line are exported whole, but stray `# Title:` / `# Slug:` lines are still lifted out. Clear the Draft marker field to disable header splitting entirely. For example, this source file: ```markdown # Title: The Gate # Slug: in which the door will not open outline: she arrives, she knocks, nothing ### Rough Draft: The prose that actually gets exported begins here. ``` exports as a chapter titled **The Gate**, captioned *in which the door will not open*, containing only the prose below the marker. ## Files the app writes | Location | Purpose | |---|---| | `/*.md` | your manuscript files | | `/order.json` | the manual ordering (committed to git) | | `/titles.json` | chapter-title overrides (committed to git) | | `~/.config/md-manuscript/config.json` | last workspace, export path, prefs | ## Markdown supported in ODT export Headings, paragraphs, **bold**, *italic*, ***both***, `inline code`, fenced/indented code blocks (monospace, whitespace preserved), ~~strikethrough~~, ordered and unordered (nested) lists, block quotes, horizontal rules, and links. Images are rendered as a text placeholder (not embedded).