Skip to content

fix: resolve input, focus, persistence, and terminal regressions - #83

Merged
simota merged 3 commits into
mainfrom
fix/static-analysis-n01-n12
Sep 10, 2026
Merged

simota merged 3 commits into
mainfrom
fix/static-analysis-n01-n12

Conversation

@simota

@simota simota commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Fix regressions in split-pane input routing, terminal margins, persistence, and modal IME placement.

  • Keep Secure Keyboard Entry enabled when focus events arrive out of order while switching between Noa windows. Route drag motion and release to the pane that received the press, and clear capture on focus loss.
  • Return an error from noa.sendText when the input queue rejects bytes or the pane is disconnected. Queue acceptance still does not guarantee that the child has consumed the input.
  • Preserve macOS Option composition classification across key presses, repeats, and releases, and use physical keypad codes for Kitty keyboard reporting.
  • Make saved primary fonts take precedence over included font families while retaining fallbacks. Use unique staging files for concurrent favorites saves, sharing the session writer's atomic replacement helper.
  • Preserve live Kitty image positions when clearing scrollback. Correct absolute cursor placement, printing, editing, and relative movement around horizontal margins; wrapping, LF, and RI outside the scroll rectangle no longer scroll its contents.
  • Anchor IME candidates to the active modal. Derive the search caret from the actual status suffix and share content-dependent palette/settings card geometry with native drawing, including short panes and mixed header/entry rows.

Validation

  • cargo test --workspace --no-fail-fast — 2,653 passed, 15 ignored on macOS outside the sandbox. The unrestricted run also passed the shared-memory and socket tests that the sandbox denied.
  • cargo build --workspace — passed.
  • cargo fmt --all --check — passed.
  • git diff --check — passed.
  • Observed failing regressions before the margin and IME fixes, then confirmed they passed. Additional cases cover wide/combining search text, truncated prompts, margin boundaries, and palette selection/height changes.

Compatibility and remaining manual checks

No persistence format or IPC schema changes. Concurrent saves remain whole-file, last-writer-wins replacements. Reverting the code requires no data migration.

Native focus transitions, cross-pane mouse gestures, and live macOS IME candidate windows have not been manually exercised or recorded; verification covers the event policies and layout calculations. Proportional-font palette/title caret X positions use a font-advance estimate.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T05:27:56.066836Z c637bd4 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c637bd40fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +197 to +203
let input_top = match state.mode() {
ThemeSettingsMode::Theme => THEME_FILTER_TOP,
ThemeSettingsMode::Settings => SETTINGS_TOP,
};
CaretPt {
x: card_x + 20.0,
y: card_top + input_top,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track the active theme-settings text field

On macOS this always anchors at the fixed top-left of the settings section. It never advances with the theme/settings search query or live preedit, and when IME is used to edit fields such as Font Family or Background Image while search is inactive, the real input is the selected settings row rather than SETTINGS_TOP. Consequently the candidate window is detached from the visible caret for every theme-settings text-entry mode; derive both coordinates from the active section/row and current buffer plus preedit.

Useful? React with 👍 / 👎.

Comment on lines +244 to +248
let card = layout.cards.iter().find(|card| card.id == session.card)?;
let rect = card.name_line;
Some((
PhysicalPosition::new(rect.x as i32, rect.y as i32),
PhysicalSize::new(1, rect.h.max(1)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Advance the sidebar rename IME anchor

During a macOS sidebar rename, this pins the IME candidate window to the left edge of name_line regardless of the existing name, appended text, or live preedit. Since the rendered rename caret is after buffer + preedit, the candidate window remains at the beginning of the field while the user types; calculate the horizontal caret position from that displayed text, with the same clipping behavior as the sidebar renderer.

Useful? React with 👍 / 👎.

Comment on lines +152 to +155
let layout = PaletteCardLayout::new(pane, snapshot);
CaretPt {
x: layout.card_x + CARD_PAD_H + 22.0 + query_chars as f64 * INPUT_FONT_ADVANCE,
y: layout.card_top + 13.0,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clamp palette IME anchors to the visible query row

For a long command-palette query or remote endpoint on macOS, query_chars * INPUT_FONT_ADVANCE grows without regard to the finite card width. Once the query exceeds roughly the visible row capacity, the returned caret passes the card and eventually the window edge even though the label is clipped, causing the candidate window to appear far from the visible input. Clamp or scroll the anchor using the query row's actual content bounds.

Useful? React with 👍 / 👎.

…ings

Ten of twelve findings from the 2026-09-10 static analysis (N01-N12);
N08 and N10 are rejected as Ghostty parity (key_encode.zig escape-encodes
under any non-zero kitty flag and sends IME/unidentified-key text raw).

- N01 secure input: decide from app-level focus (`os_focused` after the
  loss), so an outgoing window's `Focused(false)` that follows the
  successor's `Focused(true)` no longer releases Secure Keyboard Entry.
- N02 ipc: `noa.sendText` reports a dropped (queue full) or sink-less
  (disconnected) input as an error instead of `Ok`.
- N03 mouse: the left press captures its pane; motion and release of that
  gesture route to it across split dividers, with cancellation on focus
  loss, pane close, and pane move.
- N04 config writer: after a font-family save, re-parse with includes
  expanded and, when an include's family still heads the list, rewrite
  the key as reset + new primary + surviving fallbacks.
- N05 favorites: share session.rs's per-process/per-call staging file via
  a new `atomic_write` module instead of a fixed `favorites.tmp`.
- N06 grid: `clear_scrollback` shares `ED 3`'s placement collapse so live
  Kitty images keep their row when only history is cleared.
- N07 grid: with DECOM off, CUP/CHA/HPA and the DECSLRM home are bounded
  by the screen, not the left/right margins (Ghostty `setCursorPos`).
- N09 kitty: a composing macOS Option is not Alt for the escape decision;
  the composed text passes through, report-all keeps the modifier bit and
  the associated text.
- N11 kitty: physical keypad keys use their dedicated codes (KP_Enter is
  57414 even though winit's logical key is Enter).
- N12 ime: the candidate window anchors to the owning modal's input row
  (palette / remote UI / title prompt / theme settings / search prompt /
  sidebar rename) instead of the terminal cursor behind the card.
Absolute placement outside horizontal margins must not make relative
motion reverse direction or scroll unrelated cells during wrapping,
LF, or RI.

Use the rendered search status width and the palette's visible rows to
keep IME candidate anchors aligned with the active input field.
Add regressions for boundary movement, clipped search text, and short
palette panes with mixed row types.
@simota
simota force-pushed the fix/static-analysis-n01-n12 branch from c637bd4 to bafa18c Compare September 10, 2026 05:35
@simota
simota merged commit 2808d80 into main Sep 10, 2026
1 check passed
@simota simota mentioned this pull request Sep 10, 2026
@simota
simota deleted the fix/static-analysis-n01-n12 branch September 10, 2026 23:48
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.

1 participant