Nightly Build / build (push) Canceled after 10m54s
The file viewer converts word-processor documents to PDF server-side via LibreOffice (skald_core::docx::DocxConverter), mirroring the LaTeX pipeline but content-hash cached: the format is self-contained, so there is no dependency graph and the file watcher needs no expansion. Container-only documents are shuttled out and converted on the host. With no LibreOffice installed the viewer says so and falls back to download-only. Downloads still save the original document, not the preview PDF.
79 lines
7.8 KiB
Markdown
79 lines
7.8 KiB
Markdown
# The file viewer
|
|
|
|
One file, open on screen. It is where every file in the app ends up being read: the Files page and a project's explorer open into it, a path in one of your tool cards is clickable and opens it, an approval card for a write opens it — and **you can open it yourself** with `show_file_to_user`, which is the point worth remembering: when a file is the answer, put it on their screen instead of pasting it into the chat.
|
|
|
|
The header shows the file's path exactly as your tools spell it (`shared/recipes/dolci.md`, `projects/anna/holiday/plan.tex`), so a user reading it back to you is handing you a working path. Next to it: the history button, the download button, and — for HTML — a source/preview toggle.
|
|
|
|
## What it does with each kind of file
|
|
|
|
| Kind | What the user sees |
|
|
| --- | --- |
|
|
| Markdown | rendered, with images referenced relatively resolved from the file's own folder; fenced code blocks get a copy button |
|
|
| Code and plain text | the source, syntax-highlighted |
|
|
| Images (PNG, JPG, GIF, WebP, AVIF…) | the picture |
|
|
| SVG | rendered in an isolated frame — scripts inside it never run |
|
|
| PDF | drawn by the app itself, so it looks and scrolls the same in every browser and on the phone |
|
|
| LaTeX (`.tex`) | **compiled to PDF on the server** and shown as the document |
|
|
| Word documents (`.docx`, `.doc`, `.odt`, `.rtf`) | **converted to PDF on the server** (needs LibreOffice installed there) and shown as the document |
|
|
| HTML | rendered live in an isolated frame; the toggle in the header switches to the source |
|
|
| Anything else | not displayed — the file can still be downloaded |
|
|
|
|
Two consequences worth knowing:
|
|
|
|
- **Always give `show_file_to_user` the `.tex`, never a `.pdf` you built from it.** The `.tex` is recompiled and the view follows its dependencies — `\input` fragments, styles, images — so it stays current. A raw `.pdf` is served as bytes: it is never recompiled and the user ends up looking at a stale render. The same applies to word documents: give the `.docx`, not a PDF exported from it — the viewer converts it, and re-converts it when the file changes.
|
|
- **A compile that fails is not a dead end.** The viewer shows the source instead, with the actual error block foldable at the top. That error is worth reading if they ask why "the document is not showing" — it usually names a line. (For a word document there is no readable source to show, so a failed conversion explains itself in the same foldable block over the download state.)
|
|
|
|
## It is live
|
|
|
|
The viewer watches the open file. When something changes it on disk — you, from the conversation; another member; a task running in the background — the view reloads on its own within about a second, without a refresh and without losing their place.
|
|
|
|
This is what makes "watch this while I fix it" work: they leave a document open, you rewrite it, and they see the new version. There is no need to tell them to reload, and no need to reopen the file after each edit.
|
|
|
|
## Editing Markdown
|
|
|
|
A Markdown file the person may write to shows **View | Edit** tabs. Everything else is read-only, always — code, text, images, and anything under a read-only place.
|
|
|
|
- **Edit** is a plain source editor, with a dot marking unsaved changes; **View** meanwhile previews what they are typing, not what is on disk.
|
|
- **Save** writes the file. Leaving the file with unsaved changes asks first.
|
|
- **If the file changed underneath them while they were typing** — because you wrote to it, or another member did — the save does not clobber it. A banner offers three ways out: reload the other version (dropping theirs), overwrite with theirs, or copy their text to the clipboard first and then reload. If they ask you which to pick, the safe answer is copy-then-reload: nothing is lost and the two versions can be merged in conversation.
|
|
|
|
Two things that are **never** editable here, and both are deliberate rather than a limitation to work around:
|
|
|
|
- **Memory notes** (`user-memory/…`, `shared-memory/…`). They open, they read, they do not save — changing memory goes through you in conversation, which is what keeps the history honest ([memory.md](memory.md)).
|
|
- **A past version** (see below), and files read out of the sandbox that have no counterpart on disk.
|
|
|
|
## History: reading an earlier version
|
|
|
|
Files inside a folder that is under version control — in practice, project folders the project coordinator commits into — get a **clock button** in the header. It lists the changes that touched *this* file, newest first, with their date and the message that came with them.
|
|
|
|
- Picking one shows the file **as it was then**, with a banner saying which version, and a way back to the current one.
|
|
- The whole view comes from that moment, not just the text: a LaTeX file compiles against the images and fragments of that revision, and a Markdown file's pictures are the ones it had then.
|
|
- A past version is read-only, and the live watcher stands down while it is open — working-tree changes will not yank them back to the present.
|
|
- **No clock button means no history**, which is normal: memory notes, files outside any versioned folder, and instances whose host has no `git` simply never offer it. It is not an error and there is nothing to switch on.
|
|
|
|
## Download
|
|
|
|
The download button saves the file with its real name. For a `.tex` it downloads the **compiled PDF**, not the source — that is usually what someone asking to "send me the document" wants; if they want the source itself, they want the `.tex`, and it is worth checking which. A word document instead downloads as **the original file** (the `.docx`, `.odt`…): unlike a `.tex` source it is the editable document itself, and the PDF on screen is only the preview.
|
|
|
|
## What the viewer tells you
|
|
|
|
While a file is open, the eye in the chat carries its path and how it is being shown, plus any passage the user highlighted in it — with line numbers when they are looking at source. That is why "what does this mean?" or "rewrite this paragraph" works with no file named: the selection came with the message. Full details, including how to turn it off, in [view-context.md](view-context.md).
|
|
|
|
If the eye is off, none of that arrives, and you genuinely do not know what they have open — ask, rather than guess.
|
|
|
|
## Common questions
|
|
|
|
- *"Can I edit this here?"* — Markdown, in a place they may write to. Everything else is read-only in the page; ask them what to change and do it from the conversation.
|
|
- *"It says the file changed while I was editing."* — something else wrote to it. Three buttons on the banner; copy-then-reload loses nothing.
|
|
- *"The PDF is wrong / old."* — if there is a `.tex` beside it, they are looking at a stale build. Open the `.tex` instead: it recompiles.
|
|
- *"Where is the old version?"* — the clock, if the file is in a project folder. Otherwise there is no history to show, and the honest answer is that this file is not versioned.
|
|
- *"It won't show the file."* — a kind the viewer cannot render (an archive, an unknown binary) shows the download instead, and that is the whole story. An office document showing only the download means the server has **no LibreOffice installed**: the admin installing it turns the preview on — nothing to change in the app, and the foldable block on the page says exactly this.
|
|
- *"Show me that file."* — `show_file_to_user`, one file per call, on any path in their own workspace including a memory note. It must already exist.
|
|
|
|
## Related
|
|
|
|
- [files.md](files.md) — the Files page: the places a member can reach, and where write access comes from
|
|
- [projects.md](projects.md) — the project explorer, and the versioning that gives the clock button something to list
|
|
- [memory.md](memory.md) — why notes are readable here but only changeable through you
|
|
- [view-context.md](view-context.md) — what the open file and the highlighted passage send with a message
|