Skip to content

fix: search bar clipboard and focus improvements#3025

Merged
sawka merged 2 commits intowavetermdev:mainfrom
Shay12tg:main
Mar 10, 2026
Merged

fix: search bar clipboard and focus improvements#3025
sawka merged 2 commits intowavetermdev:mainfrom
Shay12tg:main

Conversation

@Shay12tg
Copy link
Contributor

Two small fixes to the in-app search feature:

  • Skip copy-on-select during search navigation — when iterating through
    search results in the terminal, the clipboard kept getting overwritten with
    the matched text on every step. This was annoying on its own, but also
    polluted paste history managers. The root cause was
    that xterm.js updates the terminal selection programmatically to highlight
    each match, which triggered the copy-on-select handler. The fix skips the
    clipboard write whenever an element inside .search-container is the active
    element.
  • Refocus search input on repeated Cmd+F — pressing Cmd+F while the search
    bar was already open was a no-op (setting the isOpen atom to true again
    has no effect). The fix detects the already-open case and directly calls
    focus() + select() on the input, so the user can immediately type a new
    query.

Navigating search results in the terminal causes xterm.js to change the
selection programmatically, which was triggering copy-on-select and
clobbering the clipboard. Skip the clipboard write when an element
inside .search-container is the active element.
Copilot AI review requested due to automatic review settings March 10, 2026 11:30
@CLAassistant
Copy link

CLAassistant commented Mar 10, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

Walkthrough

Changes add a focus-control mechanism for the search input and adjust copy-on-select behavior. keymodel.ts now increments a block-specific focusInput counter when activating an already-open search instead of always reopening it. search.tsx introduces a focusInput atom, threads it through the Search component and useSearch API, and uses an input ref to programmatically focus/select the input when focusInput is incremented; it also resets the counter on close. termwrap.ts skips copy-on-select when the focused element is inside a search container. frontend/types/custom.d.ts adds the focusInput type to SearchAtoms.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: improvements to search bar clipboard handling and input focus behavior.
Description check ✅ Passed The description is well-detailed and directly relates to the changeset, explaining both the clipboard issue and the refocus problem with specific context.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 10, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • frontend/app/element/search.tsx - Adds focusInput atom and effect to focus search input
  • frontend/app/store/keymodel.ts - Search UX: increments focusInput counter when search already open
  • frontend/app/view/term/termwrap.ts - Prevents copy-on-select when search bar has focus
  • frontend/types/custom.d.ts - TypeScript: adds focusInput to SearchAtoms type

Summary

This PR implements two UX improvements for the in-app search:

  1. Search refocus (keymodel.ts, search.tsx): When Cmd+F is pressed while search is already open, the input is now focused and all text is selected. This uses a focusInput counter pattern - instead of using a global DOM query (which could target the wrong block), the counter is incremented and each SearchComponent checks if it's their turn to focus.

  2. Copy-on-select guard (termwrap.ts): Prevents automatic clipboard copying when the search bar has focus, avoiding unintended copies during search result navigation.

Note on Existing Comment

The existing inline comment about document.querySelector(".search-container input") was made on an earlier version of the code. The current implementation has been updated to use the focusInput counter pattern, which avoids the global DOM query issue entirely. This addresses the concern raised in the comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
frontend/app/store/keymodel.ts (1)

698-706: Global DOM query may select wrong search input when multiple blocks have search open.

document.querySelector(".search-container input") returns the first matching element in DOM order, not necessarily the one belonging to the currently focused block. If multiple blocks have their search panels open, this could focus the wrong input.

Consider scoping the query to the focused block's container, or adding a ref to SearchAtoms for direct access.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/store/keymodel.ts` around lines 698 - 706, The DOM query using
document.querySelector in the block that checks
globalStore.get(bcm.viewModel.searchAtoms.isOpen) may pick the first
.search-container input in the whole page, so change it to target the input for
the currently focused block instead: locate the block/container that owns the
active search (e.g., use the focused block element or a block-specific
identifier) and run querySelector on that container, or better, add and use a
ref on the SearchAtoms component to directly access its input; update the logic
around globalStore.set(bcm.viewModel.searchAtoms.isOpen) and the focus/select
calls to use that scoped container or ref so the correct input is focused and
selected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/app/store/keymodel.ts`:
- Around line 698-706: The DOM query using document.querySelector in the block
that checks globalStore.get(bcm.viewModel.searchAtoms.isOpen) may pick the first
.search-container input in the whole page, so change it to target the input for
the currently focused block instead: locate the block/container that owns the
active search (e.g., use the focused block element or a block-specific
identifier) and run querySelector on that container, or better, add and use a
ref on the SearchAtoms component to directly access its input; update the logic
around globalStore.set(bcm.viewModel.searchAtoms.isOpen) and the focus/select
calls to use that scoped container or ref so the correct input is focused and
selected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a0451ce5-992e-4a9a-9214-c5465e55cc65

📥 Commits

Reviewing files that changed from the base of the PR and between 7119970 and 602a6e5.

📒 Files selected for processing (2)
  • frontend/app/store/keymodel.ts
  • frontend/app/view/term/termwrap.ts

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the in-app search UX by preventing unintended clipboard writes during search-result navigation in terminal blocks, and by ensuring repeated Cmd+F refocuses the existing search input.

Changes:

  • Skip terminal copy-on-select when focus is inside the search UI, avoiding clipboard pollution during search navigation.
  • When search is already open, Cmd+F now focuses and selects the search input instead of being a no-op.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
frontend/app/view/term/termwrap.ts Prevents copy-on-select from firing while the search UI is focused (avoids overwriting clipboard during result navigation).
frontend/app/store/keymodel.ts Enhances Cmd+F behavior to refocus/select the search input if search is already open.

When the search bar was already open, Cmd+F was a no-op because setting
the isOpen atom to true again had no effect. Fix uses a per-instance
focusInput atom (a monotonic counter) on SearchAtoms: activateSearch
increments it for the focused block's search instance, and SearchComponent
watches it to call focus()+select() on its own inputRef — avoiding a
global DOM query that would target the wrong block when multiple searches
are open simultaneously. The counter is reset to 0 on close so re-opening
doesn't re-trigger the focus effect.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
frontend/app/element/search.tsx (1)

63-70: Consider adding isOpen to the dependency array or suppressing the lint warning.

The effect reads isOpen but only lists focusInputCounter as a dependency. While the logic appears intentional (initial open is handled by autoFocus, and this effect only reacts to explicit focus requests), this will trigger ESLint's react-hooks/exhaustive-deps rule. Adding isOpen to the dependency array is safe here since the counter resets to 0 on close, making the condition focusInputCounter > 0 && isOpen effectively guarded.

♻️ Suggested fix
     useEffect(() => {
         if (focusInputCounter > 0 && isOpen) {
             inputRef.current?.focus();
             inputRef.current?.select();
         }
-    }, [focusInputCounter]);
+    }, [focusInputCounter, isOpen]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/element/search.tsx` around lines 63 - 70, The useEffect that
focuses the input (the effect referencing focusInputCounter, isOpen, and
inputRef.current) currently only lists focusInputCounter in its dependencies
which triggers react-hooks/exhaustive-deps; update the dependency array to
include isOpen as well (i.e., useEffect(..., [focusInputCounter, isOpen])) so
the hook correctly re-evaluates when open state changes, or alternatively add an
explicit eslint-disable-next-line comment if you intentionally want to suppress
the rule; locate the effect in the Search component (the useEffect that focuses
and selects inputRef.current) and apply the dependency change or lint
suppression accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/app/element/search.tsx`:
- Around line 63-70: The useEffect that focuses the input (the effect
referencing focusInputCounter, isOpen, and inputRef.current) currently only
lists focusInputCounter in its dependencies which triggers
react-hooks/exhaustive-deps; update the dependency array to include isOpen as
well (i.e., useEffect(..., [focusInputCounter, isOpen])) so the hook correctly
re-evaluates when open state changes, or alternatively add an explicit
eslint-disable-next-line comment if you intentionally want to suppress the rule;
locate the effect in the Search component (the useEffect that focuses and
selects inputRef.current) and apply the dependency change or lint suppression
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bb523fdf-0389-4c32-8a60-f60443825165

📥 Commits

Reviewing files that changed from the base of the PR and between 602a6e5 and 1c106fb.

📒 Files selected for processing (3)
  • frontend/app/element/search.tsx
  • frontend/app/store/keymodel.ts
  • frontend/types/custom.d.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/app/store/keymodel.ts

@sawka
Copy link
Member

sawka commented Mar 10, 2026

@Shay12tg thanks for this thoughtful and targeted contribution. Just tested, works great.

@sawka sawka merged commit 29f49dc into wavetermdev:main Mar 10, 2026
3 checks passed
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.

4 participants