research feasibility of previewing markup in markdown and org-mode in editable areas
markup previews #235
Discussion
Feasible, as a server round-trip. Findings and a proposed shape.
What exists. Every stored body already renders through one function, =ugcHTML(raw, format)= in =internal/httpd/web.go= (goldmark for =md=, go-org plus bluemonday for =org=), and =s.ugcFor(r, repo)= wraps it with the viewer's autolinks. A preview needs no new renderer and no new control command: the capability is rendering, which is already there; the preview is a web affordance on the form, like the format picker.
What rules out a live preview. The CSP is =script-src 'none'= and =internal/web/static= holds no JavaScript, stated as policy in =README.org=, =Threat-Model=, and both web design plans. =/api/v1/cmd= is bearer-token only, with no cookie fallback, so a page could not call it even with a script. So there is no typing-as-you-go preview without reversing a design decision, and I do not recommend reversing it for this.
The shape that fits. A second submit button on each markup form, =Preview=, posting to the same action behind the same =checkOrigin(requireUser(...))=. The handler sees =preview= set, writes nothing, and re-renders the page with the rendered body in a =.rendered= block above the textarea, textarea and format select still populated. This is the same pattern as the blob page's =?view=source= toggle and the =cmtln= anchor travelling in the query: one round trip, no script. The preview markup is the same partial the thread uses, so what you see is what the comment will be, autolinks included.
Forms that take markup (textarea name, template):
- =body=: issue create (=issuenew.html=), issue edit and comment (=issue.html=), MR create (=mrnew.html=), MR edit and comment (=mr.html=), diff-line comment and thread reply (=layout.html=, always markdown)
- =notes=: release create and edit (=releases.html=)
- =about=: profile (=account.html=)
- =content=: the file editor (=edit.html=), which is the wiki editor too since wikis are =.gitbay/wiki/= files
Not applicable: snippets are highlighted, not rendered.
Cost. Each of the twelve forms is a button, an =if r.FormValue("preview") != ""= branch before the dispatch in its submit handler, and a page field for the rendered HTML. The create forms are the cheap ones (the page is the form). The issue and MR pages re-render the whole thread with the preview above the compose box, which is fine on one column. The file editor should preview only when the path ends in =.md=, =.markdown= or =.org=, through =renderReadme= so headings and relative links match the blob view. The diff-line forms live inside the diff and I would leave them out of a first cut. Rough size: one MR, about 250 lines of Go and templates plus an e2e test per surface, following the existing =formatpickerweb_test.go= shape.
Parity. A new row =preview body markup= under issues, MRs, releases and profile: cli =n/a=, web =yes=, ios =yes= where the app already renders locally with OrgSwift. Worth noting there: the web preview is go-org's rendering and the app's is OrgSwift's, and go-org is not yet on the =krz/org-conformance= corpus, so an org preview can differ between the two surfaces until it is.
Recommend: go ahead with the round-trip preview on the create and comment forms, releases and profile first; file editor second. Say the word and I will file it as a plan.
related bug to fold into this: markup for md/org don't apply to comments on issues (like this one right now), but it should. markup should apply to all comments, not just the original issue
closed by cmc in commit 929f2440bf: web: preview markup before writing it
2026-09-19 20:07 UTC