logs.gokuls.in

7 pull requests merged across 2 repos

bahdotsh/mdterm

  • Inline links no longer show the raw URL after the link text — just the text, like GitHub renders it (fixes #22)
  • Link picker (f key) now shows text → URL for each entry instead of just the URL, and same-URL links with different text get separate entries (fixes #23)

Changes

  • markdown.rs: Remove URL span from End(TagEnd::Link) handler
  • viewer.rs: Replace URL-based dedup with adjacency-based merging for link extraction; update overlay to render text → URL with distinct colors

Test plan

  • Open test.md, verify links show only text inline (no URL appended)
  • Press f, verify each link shows "text → URL" format
  • Confirm same-URL links (readme 1, readme 2) appear as separate entries
  • Image links still show URL-only in the picker

Closes #22, closes #23

  • Move all expensive image work (Lanczos3 resize, PNG/Sixel/base64 encode) to background threads — the main thread never touches image pixels, eliminating UI hangs during image loading
  • Replace rebuild() with lightweight finalize_layout() when image fetches complete — adjusts placeholder rows and rebuilds indices without re-parsing the entire markdown document
  • Store raw images as Arc<DynamicImage> to avoid cloning large pixel buffers when handing off to pre-render threads

Details

The old code fetched images in the background but ran pre_render() synchronously on the main thread. For large images this meant hundreds of milliseconds of Lanczos3 resizing and protocol-specific encoding blocking the event loop. It also called rebuild() (full markdown re-parse) on every single image completion.

Now there are two background channels:

1. Fetch channel (existing) — downloads/decodes raw images

2. Render channel (new) — resizes and encodes for the target protocol (Kitty/iTerm2/Sixel/HalfBlock)

Results from stale terminal widths or cancelled file switches are automatically discarded. The viewer shows a "Loading" placeholder until both fetch and pre-render complete.

Test plan

  • cargo build — compiles cleanly
  • cargo test — all 120 tests pass
  • cargo clippy — no warnings
  • Manual: open a markdown file with multiple remote images, verify smooth scrolling during load
  • Manual: resize terminal while images are loading, verify images re-render at correct size
  • Manual: switch files while images are loading, verify no stale images appear
  • Replace transient status bar messages with a centered toast overlay (auto-expires after 1s)
  • Click-to-copy: click any heading section, list, or code block to copy its content to clipboard
  • Add LineMeta::ListItem { list_id } to track list membership for whole-list copy
  • Pre-compute TOC section ranges and content for instant heading-section copy
  • Pointer cursor shown over all copyable elements (headings, lists, code blocks)
  • Fix UTF-8 panic in heading label truncation (byte-index slice → char-safe truncation)
  • Fix toast overlay positioning to account for title bar and clamp on small terminals
  • Update README to reflect new click-to-copy behavior

Test plan

  • Click a code block → toast says "Code block copied", clipboard has the code
  • Click a heading line → toast says "Copied: <heading>", clipboard has the full section text
  • Click a list item → toast says "List copied", clipboard has the entire list
  • Click a link → still opens/navigates as before (no copy)
  • Hover over code/heading/list → pointer cursor appears
  • Hover over normal text → default cursor
  • Toast disappears after ~1 second
  • Y still copies full document, c still copies nearest code block
  • Test with a heading containing emoji/CJK characters — no panic on click
  • Resize to a very small terminal — toast stays within bounds
  • Resolve relative markdown links (e.g. docker.md, ./foo.md, file.md#section) against the current file's directory and open them in the viewer instead of showing "unsupported URL scheme"
  • Add a navigation history stack with Backspace to go back to the previous file and scroll position
  • Add test files (test.md section + test_linked.md) to exercise local link navigation

Closes #11

Test plan

  • cargo run -- test.md, press f, select a local file link — it opens in the viewer
  • Press Backspace — returns to test.md at the original scroll position
  • Try the anchor link (test_linked.md#heading-for-anchor-test) — opens file and scrolls to heading
  • Try the nonexistent link — shows blocked message
  • Click a local file link directly with mouse — same behavior
  • Press F1 — help screen shows Backspace keybinding
  • cargo test passes, cargo clippy clean

Adds Sixel image protocol support as a middle tier between iTerm2 and the Unicode half-block fallback. Terminals like foot, mlterm, mintty, and contour can now render actual pixel-level images instead of the half-block approximation.

  • Zero new dependencies — Sixel encoding implemented in-house (median-cut quantization to 256 colors, 6-row band encoding with RLE compression)
  • Auto-detection for known Sixel terminals via TERM_PROGRAM / TERM env vars
  • Manual override via MDTERM_IMAGE_PROTOCOL=sixel for terminals not auto-detected
  • Block rendering with crop caching for smooth scrolling (same pattern as iTerm2 path)
  • 8 new unit tests covering encoding, RLE, and quantization

Protocol priority

Kitty > iTerm2 > Sixel > HalfBlock

Terminals that support multiple protocols (e.g. WezTerm supports both Kitty and Sixel) will use the most efficient one.

Auto-detected Sixel terminals

TerminalDetection method
footTERM_PROGRAM=foot or TERM=foot/foot-extra
mltermTERM_PROGRAM=mlterm or MLTERM env var
minttyTERM_PROGRAM=mintty
contourTERM_PROGRAM=contour

Test plan

  • cargo check — compiles clean
  • cargo clippy — zero warnings
  • cargo test — all 117 tests pass (109 existing + 8 new)
  • cargo build --release — release build succeeds
  • Manual test on a Sixel-capable terminal (e.g. MDTERM_IMAGE_PROTOCOL=sixel mdterm README.md)

— mouse capture was grabbing all events, preventing text selection and link clicks.

  • Click to open links: Left-clicking a link in the rendered markdown opens it in the default browser (uses the same open::that() as the link picker)
  • Hover cursor: Mouse pointer changes to a hand cursor (OSC 22) when hovering over links, resets when moving off. Terminals that don't support OSC 22 silently ignore it
  • Mouse capture toggle (m): Press m to disable mouse capture entirely so the terminal can handle text selection natively. Press again to re-enable scroll wheel support. Status message confirms the state

Test plan

  • cargo clippy — no warnings
  • cargo test — 102 passed, 0 failed
  • Open a markdown file with links, verify left-click opens them in browser
  • Hover over a link and verify cursor changes to pointer (in supported terminals: kitty, foot, xterm)
  • Press m to toggle mouse capture off, verify text selection works
  • Press m again, verify scroll wheel works
  • Verify F1 help screen shows the new m keybinding

ratatui/awesome-ratatui

Four new ratatui-based projects:

  • giff: TUI for git diffs with interactive rebase
  • wrkflw: TUI for validating GitHub Actions locally
  • blogr: static site generator with a terminal editor
  • snipt: text snippet expansion with a TUI manager

<!-- Thanks for making Ratatui awesome! 🐭 -->

  • Link to your project (GitHub/crates.io):
  • https://github.com/bahdotsh/giff
  • https://github.com/bahdotsh/wrkflw
  • https://github.com/bahdotsh/blogr
  • https://github.com/snipt/snipt
  • Description (optional):

Four ratatui-based TUI tools:

  • giff: git diffs with interactive rebase
  • wrkflw: validate/execute GitHub Actions locally
  • blogr: terminal-based static site generator with TUI editor
  • snipt: text snippet expansion with TUI manager

giff

!giff demo

wrkflw

!wrkflw demo

blogr

!blogr demo

snipt

!snipt screenshot

-->