Skip to content

Fix open issues #3–#9: full-file diffs, faster startup, and more - #11

Merged
bmannakee merged 1 commit into
mainfrom
open-issues
Nov 3, 2026
Merged

bmannakee merged 1 commit into
mainfrom
open-issues

Conversation

@bmannakee

Copy link
Copy Markdown
Owner

Summary

Fixes every open issue in one PR, as asked.

  • Expand diffs to the whole file #9 Full-file view. z a (⌥⌘E, View menu) switches the current file between its hunks and the whole file. z R / z M do it for every file, and [diff] view = "full" in config.toml opens files in full. Hunk navigation (} / {) still jumps between the changes, and the cursor stays on the same line when you switch. The cursor moves through every line, but GitHub only takes comments on lines in the diff. Tested: for a line outside the diff, GitHub returns a null thread instead of an error. So the extra lines are view-only, and c on one shows a note under the diff.
  • App is slow to open or come into focus from the Dock #8 Slow to open or focus.
    • The app now activates after launch finishes. Before, it asked in init, and that request can be ignored.
    • The review queue's list is shared between windows. A Dock click that opens a new window shows the last list at once, and only refetches if the list is more than a minute old.
    • gh now runs without blocking threads while it waits. Before, each call held up to three pool threads, which could starve the app's other async work when several windows loaded at once.
    • New scripts/bundle builds .build/Maser.app, signed ad hoc. That's also the likely path for the work Mac: build and sign there, with no developer account.
  • Find gh outside Homebrew/system paths #7 Finding gh. Maser now also looks in MacPorts, Nix, ~/.local/bin, ~/bin and mise or asdf shims, then asks the login shell (5 s timeout). [github] gh = "…" in config.toml overrides the search.
  • Relative times in the conversation go stale #6 Stale relative times. The conversation re-renders every minute while it's showing, and only reloads the page when the text actually changed. Items older than 30 days show a date, as on github.com.
  • target=_blank links in the conversation don't open #5 target="_blank" links. Confirmed that GitHub wraps images in <a target="_blank"> (seen in cli/cli bodies). Those clicks did nothing; they now open in the browser.
  • Paginate capped GraphQL lists (comments, thread comments, checks) #4 Capped lists. Conversation comments, reviews and checks request totalCount. When there's more than one page, the full list is fetched with --paginate. Threads with more than 100 comments fetch the rest the same way. Labels and review requests go from 50 to 100.
  • Unquote git-quoted paths in DiffParser #3 Quoted paths. DiffParser unquotes git's C-quoted paths (octal UTF-8 bytes, \t, \", \\) in diff --git, --- / +++ and rename lines.

Also fixed: addReviewThread used to report success when GitHub returned a null thread. It now throws a clear error.

Closes #3, closes #4, closes #5, closes #6, closes #7, closes #8, closes #9.

Implementation notes

  • Merging the whole file. This is MaserCore's FileDiff.fullFile(headText:).
    • It checks every line of the diff against the fetched file, and refuses if they differ.
    • It fills each gap from the hunk headers, numbering both sides.
    • It renumbers IDs in display order, since ranges and hunk navigation compare IDs.
    • Filled-in lines are isExpansion hunks and lines. commentSide is nil for them; the new cursorLines includes them.
  • Fetching contents. File contents come from repos/{owner}/{repo}/contents/{path}?ref={headRefOid} with the raw media type, capped at 4 MB. ReviewContext now also carries headCommitID.
  • Keeping the cursor in place. ReviewModel.preservingCursor(_:) maps the cursor and selection between views by line numbers, falling back to the next nearest line. Refreshes go through it too, so a refresh keeps the cursor where it was.
  • Comment highlights. CommentTarget.lineIDs is gone. Highlights are looked up by line number (FileDiff.lineIDs(for:)), so they survive switching views.
  • Settings. A new Settings type (MaserCore) reads [diff] and [github], and ConfigStore publishes it. The starter config lists both sections commented out. AGENTS.md now says where new settings go.
  • Finding gh. GitHubCLI() no longer throws, so finding gh (which may ask the login shell) never runs on the main thread. It happens on the first call and is cached.

Testing

Not checked by hand (the screen was locked):

  • whether focusing from the Dock is now fast;
  • the full-file view on screen: hidden hunk headers, the status line, cursor and scroll position after z a / z R / z M, and after a refresh;
  • the View menu items and the full file hint in the key bar;
  • clicking an image in the conversation;
  • whether the minute timer updates "N minutes ago" without moving the scroll position.

🤖 Generated with Claude Code

- #9 Full-file view: `z a` (⌥⌘E) shows the whole file instead of the
  hunks, `z R` / `z M` do it for every file, and `[diff] view = "full"`
  makes it the default. Files are fetched at the head commit on demand,
  cached per commit, and merged with the hunks in MaserCore
  (`FileDiff.fullFile(headText:)`). The cursor moves through every line;
  GitHub only takes comments on lines in the diff, so the extra lines
  are read-only, with a note under the diff if you press `c` on one.
- #8 Startup and focus: activate after launch finishes instead of in
  `init`, keep the review queue's list between windows (a Dock click
  shows it at once and refetches only if older than a minute), and run
  `gh` without blocking threads while waiting. Adds `scripts/bundle`,
  which builds Maser.app signed ad hoc.
- #7 Finding gh: also look in MacPorts, Nix, ~/.local/bin, ~/bin and
  mise/asdf shims, then ask the login shell; `[github] gh` overrides.
- #6 Conversation times re-render every minute and show a date after
  30 days.
- #5 Links with target="_blank" (GitHub wraps images in them) open in
  the browser.
- #4 Conversation comments, reviews, checks and long review threads are
  fetched in full when GitHub has more than one page.
- #3 Quoted paths in diff headers (non-ASCII names) are unquoted.

Also: `addReviewThread` now throws when GitHub answers with a null
thread, which it does for lines outside the diff instead of an error.
Non-key settings live in a new `Settings` type read from config.toml.

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

Copy link
Copy Markdown
Owner Author

LGTM. OK to merge and close

@bmannakee
bmannakee merged commit d37cd39 into main Nov 3, 2026
@bmannakee
bmannakee deleted the open-issues branch November 3, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant