Commit Graph
25 Commits
Author SHA1 Message Date
Brooklyn Nicholson bd66e55a02 fix(tui): track rendered spaces for selection copy
- add a written-cell bitmap so selection can distinguish rendered spaces from blank padding
- preserve code indentation without markdown-specific rendering hacks
2026-04-25 15:21:26 -05:00
Brooklyn Nicholson 1735ced93b fix(tui): preserve code block indentation in selection
Render code indentation spaces as selectable cells so copied fenced code keeps its leading whitespace.
2026-04-25 15:17:36 -05:00
Brooklyn Nicholson b97b4c4981 refactor(tui): clean markdown.tsx per KISS/DRY
- Drop the outer no-op capture group from INLINE_RE and restructure the
  source as an ordered list of patterns-with-index-comments so each
  alternative is individually greppable. Shift group indices in MdInline
  down by one accordingly.
- Inline single-use helpers (parseFence, isFenceClose, isMarkdownFence,
  trimBareUrl) and intermediate variables (path, lang, raw, prefix, body,
  depth, task body, setext match, etc.).
- Hoist block-level regexes used inside MdImpl (FENCE_CLOSE_RE, SETEXT_RE,
  BULLET_RE, TASK_RE, NUMBERED_RE, QUOTE_RE) to top-level consts so
  they're compiled once instead of per-line.
- Collapse the duplicate compact-vs-normal blank-line branches into one
  if/!compact gap call.
- Move Fence and MdProps types to the bottom per house style.
- Shorten splitTableRow → splitRow and use optional chaining in a few
  match sites.

No behavior change; 162/162 tests pass. Net -22 LoC.
2026-04-21 18:11:12 -05:00
Brooklyn Nicholson 43eb1153e9 fix(tui): don't swallow Kimi/Qwen ~! ~? kaomoji as subscript spans
The inline markdown regex had `~([^~\s][^~]*?)~` for Pandoc-style subscript
(H~2~O, CO~2~). On models that decorate prose with kaomoji like `thing ~!`
and `cool ~?` — Kimi especially — the opener `~!` paired with the next
stray `~` on the line and dim-formatted everything between them with a
leading `_` character, mangling markdown output.

Tighten the pattern to short alphanumeric-only content (`~[A-Za-z0-9]{1,8}~`)
since real subscript never contains punctuation, spaces, or long runs.
Same tightening applied to stripInlineMarkup so width measurement stays
consistent. Classic CLI was unaffected because it renders these literally.
2026-04-21 17:34:48 -05:00
Brooklyn Nicholson 136519a2c9 fix(tui): inject VS16 so text-default emoji render as color glyphs
Models frequently emit bare codepoints like U+26A0 (⚠), U+2139 (ℹ),
U+2764 (❤), U+2714 (✔), U+2600 (☀), U+263A (☺) which, per Unicode, have
Emoji_Presentation=No and render as monochrome text-style glyphs in
terminals unless followed by VS16 (U+FE0F). Agent output leaked through
the TUI like `⚠ careful` instead of `⚠️ careful`.

Added `ensureEmojiPresentation` (lib/emoji.ts): scans for the curated
set of text-default codepoints and appends VS16 when the next char is
not already VS16, ZWJ, or a keycap-enclosing mark. Idempotent and
fast-pathed by a Unicode-range regex so ASCII-heavy text is untouched.

Applied once at the top of `Md`'s line parse. Hermes-ink's stringWidth
already accounts for VS16, so cursor/layout stays correct.
2026-04-21 15:52:39 -05:00
Brooklyn Nicholson 97c2da2112 fix(tui): render MEDIA: as a clickable file chip, drop audio directive
The agent emits `MEDIA:<path>` to signal file delivery to the gateway,
and `[[audio_as_voice]]` as a voice-delivery hint. The gateway strips
both before sending to Telegram/Discord/Slack, but the TUI was rendering
them raw through markdown — which is also how the intraword underscore
bug originally surfaced (`browser_screenshot_ecc…`).

At the `Md` layer, detect both sentinels on their own line:
- `MEDIA:<path>` → `▸ <path>` with the path rendered literal and wrapped
  in a `Link` for OSC 8 hyperlink support (absolute paths get a
  `file://` URL, so modern terminals make them click-to-open).
- `[[audio_as_voice]]` → dropped silently; it has no meaning in TUI.

Covers tests for quoted/backticked MEDIA variants, Windows drive paths,
whitespace, and the inline-in-prose case (left untouched — still
protected by the intraword-underscore guard).
2026-04-20 17:11:54 -05:00
Brooklyn Nicholson b17eb94907 fix(tui): don't italicize intraword underscores in markdown
The inline markdown regex matched `_..._` / `__...__` anywhere, so file
paths like `browser_screenshot_ecc1c3feab.png` got mid-path italics.

Require non-word flanking (`(?<!\w)` / `(?!\w)`) on underscore emphasis
so snake_case identifiers and paths render literally, matching the
CommonMark intraword rule. `*` / `**` keep intraword semantics.
2026-04-20 17:04:09 -05:00
Brooklyn Nicholson 5c8b291607 fix(tui): wrap markdown links in Link so Ghostty/iTerm/kitty get real OSC 8 hyperlinks
renderLink was discarding the URL entirely — it rendered the label as amber
underlined text and dropped the href. Result: Cmd+Click / Ctrl+Click did
nothing in any terminal, including Ghostty.

Now both markdown links `[label](url)` and bare `https://…` URLs are wrapped
in @hermes/ink's Link component, which emits OSC 8 (\\x1b]8;;url\\x07label\\x1b]8;;\\x07)
when supportsHyperlinks() returns true. ADDITIONAL_HYPERLINK_TERMINALS already
includes ghostty, iTerm2, kitty, alacritty, Hyper.

Autolinks that look like bare emails (foo@bar.com) now prepend mailto: in the
href so they open the mail client correctly.

Also adds a typed declaration for Link in hermes-ink.d.ts.
2026-04-18 14:39:24 -05:00
Brooklyn Nicholson f8becbfbea feat(tui): per-language syntax highlighting in markdown code fences
Adds a minimal hand-rolled highlighter for ts/js/jsx/tsx, py, sh/bash, go, rust,
json, yaml, sql. Recognizes whole-line comments, single/double/backtick strings,
numbers, and per-language keyword sets. Unknown langs fall through to the current
plain rendering; the existing diff-specific colorization is preserved.

Closes the §8 "Markdown syntax highlighting is missing (only diff gets colored)"
finding from the TUI v2 audit without pulling in a highlighter library.
2026-04-18 09:48:38 -05:00
Brooklyn Nicholson 4b4b4d47bc feat: just more cleaning 2026-04-15 14:14:01 -05:00
Brooklyn Nicholson 4a260b51fe fix: deep markdown parsing 2026-04-13 15:01:15 -05:00
Brooklyn Nicholson e03bef684e chore: fmt 2026-04-12 16:33:25 -05:00
Brooklyn Nicholson 24a498eb90 feat: better markdown 2026-04-11 17:15:36 -05:00
Brooklyn Nicholson 8760faf991 feat: fork ink and make it work nicely 2026-04-11 11:29:08 -05:00
Brooklyn Nicholson b7d4ea1550 feat: better hyperlink formatting 2026-04-09 15:13:43 -05:00
Brooklyn Nicholson b50d81f212 fix: diff colours 2026-04-08 12:11:55 -05:00
Brooklyn Nicholson 9c2c9e3a3e chore: fmt 2026-04-07 20:30:22 -05:00
Brooklyn Nicholson d9d0ac06b9 chore: readme update 2026-04-07 20:24:46 -05:00
Brooklyn Nicholson 29f2610e4b tui updates for rendering pipeline 2026-04-07 20:11:05 -05:00
Brooklyn Nicholson 2d349bbf7a chore: fmt 2026-04-06 18:43:00 -05:00
Brooklyn Nicholson afd670a36f feat: small refactors 2026-04-06 18:38:13 -05:00
Brooklyn Nicholson 5a5d90c85a chore: formatting etc 2026-04-03 20:14:57 -05:00
Brooklyn Nicholson 56a69e519b chore: uptick 2026-04-03 19:55:15 -05:00
Brooklyn Nicholson 1218994992 chore: uptick 2026-04-03 14:44:50 -05:00
Brooklyn Nicholson bbba9ed4f2 feat: split apart main.tsx 2026-04-02 20:39:52 -05:00