Linked Markdown and text scripts: re-read on Play, Markdown stripping, page splitting by msevans770 · Pull Request #130 · f/textream · GitHub
Skip to content

Linked Markdown and text scripts: re-read on Play, Markdown stripping, page splitting - #130

Open
msevans770 wants to merge 14 commits into
f:masterfrom
msevans770:pr/markdown-linked-scripts
Open

msevans770 wants to merge 14 commits into
f:masterfrom
msevans770:pr/markdown-linked-scripts

Conversation

@msevans770

@msevans770 msevans770 commented Oct 7, 2026 •

Copy link
Copy Markdown

Summary

Adds linked Markdown / text scripts to the macOS app. You can open (Cmd-O), drag in, or Finder-open a .md, .markdown or .txt file, and Textream links to it instead of copying it. Each time you press Play, the file is re-read, stripped to speakable text and split into pages, so you can keep editing the script in Obsidian (or any editor) and just press Play.

macOS only. Nothing under TextreamiOS/ is touched.

Behaviour

  • Linking: open, drop or Finder-open the file. A banner shows "Linked to " and the editor becomes read-only.
  • Re-read on Play: the file is re-read when Play starts (never while the prompter is running).
  • Unlink: a button turns the pages into normal editable pages.
  • Persistence: the link survives relaunch via a security-scoped bookmark (the sandboxed App Store build has files.user-selected.read-write).
  • Safety: Save / Save As while linked only ever writes a .textream snapshot, never the source file. If the file goes missing or unreadable, the last good text is kept, a warning is shown, and Play still works.
  • While linked: Add Page, Delete Page and the dictation mic are disabled, and director-mode text is ignored, so linked pages can't be overwritten.
  • Finder: Textream appears under "Open With" for .md and .txt at Alternate rank, so it never takes over as the default app.

Markdown handling (MarkdownScriptParser)

Foundation-only, so it is unit-testable.

  • Pages split on --- rules and # / ## headings. ### and below stay inside their section. A heading only starts a new page once the current page has 40+ words, so short sections do not become tiny prompter pages.
  • Stripped: frontmatter, fenced code, <!-- --> and %% %% comments, images/embeds, footnotes, HTML tags, emphasis markers, list/task/quote/callout markers.
  • [text](url) becomes text, [[Page|Alias]] becomes Alias, tables flatten to rows of cell text.
  • Teleprompter cue brackets such as [pause] and [smile] are preserved, since the editor and speech tracker already treat them specially.
  • .txt files get no Markdown stripping.

Opinionated rules, happy to drop any of these

These come from running it over a real Obsidian vault, and are the parts you may not want upstream:

  • inline #hashtags are removed, and Tags: / Status: lines are dropped
  • a leading date/timestamp line is dropped
  • a trailing References section (any heading level) is dropped when the note has other pages

Each is a small, isolated rule in MarkdownScriptParser.swift.

Implementation

  • MarkdownScriptParser.swift and LinkedScriptStore.swift (bookmarks, UTF-8 / UTF-16 / Latin-1 decoding) are new and import only Foundation.
  • TextreamService gains the link state and openScriptFile / linkScript / refreshLinkedScript / unlinkScript / restoreLinkedScript, and routes opens by extension.
  • ContentView gets the banner, read-only editor, disabled controls and .md drop handling. HighlightingTextEditor gets an isEditable parameter.

Testing

  • 70 unit tests for the parser and file reader, run with cd Textream && swift test. The Xcode project has no macOS test target, so Textream/Package.swift is a small SwiftPM harness that compiles just the two Foundation-only files. It is only for tests and is safe to drop if you prefer another setup.
  • The Textream macOS scheme and the TextreamiOS scheme both build.
  • Run by hand on several hundred Obsidian notes (page counts and output reviewed).
  • Not tested: the App Store sandbox path, since I built locally with ad-hoc signing.

This was built with AI assistance (Claude Code), with automated review passes and unit tests, and manual runs on real notes. Happy to split it up (parser first, then UI) if that is easier to review.

🤖 Generated with Claude Code

msevans770 and others added 14 commits October 7, 2026 11:26
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…n parser

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ferences footer

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…sted-bracket links

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…lways splits

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
veysiemrah added a commit to veysiemrah/textream-windows that referenced this pull request Oct 19, 2026
Many presenters keep their talk as Markdown in a notes app. The open
dialog now takes .md and .txt as well as .textream: Markdown keeps what
is read aloud and drops the formatting (heading marks, emphasis, link
URLs, images, code blocks, comments, frontmatter), and a horizontal
rule becomes a paragraph break. Plain text is read as it is. Saving
still writes .textream. After upstream f/textream#130, without its
Obsidian-specific rules and page splitting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants