Skip to content

feat(regex-tester): add match navigation - #419

Merged
anurag629 merged 2 commits into
codercops:developfrom
kachamsiddarth:feat/380-regex-match-navigation
Oct 30, 2026
Merged

anurag629 merged 2 commits into
codercops:developfrom
kachamsiddarth:feat/380-regex-match-navigation

Conversation

@kachamsiddarth

Copy link
Copy Markdown
Contributor

What and why

Closes #380

Adds Previous match and Next match navigation to the Regex Tester, allowing users to navigate between displayed regex matches without manually scrolling through the input.

  • Displays the active match position in a Match X of Y status indicator.
  • Highlights the active match with a theme-aware outline.
  • Scrolls the active match into view without moving focus away from the navigation buttons.
  • Wraps navigation from the last match to the first and vice versa.
  • Resets the active selection when the pattern, flags, or test input changes.
  • Disables navigation when the pattern is invalid or no matches are available.
  • Handles zero-length matches with visible markers.
  • Respects the existing 1,000-match limit.
  • Keeps all processing in the browser.

How I tested this

  • Focused Regex Tester tests: 62 passed.
  • Full test suite (npm run test): 2,455 passed across 65 files.
  • Lint (npm run lint): passed, with 11 warnings in untouched files.
  • Production build (npm run build): passed.
  • git diff --check: passed.
  • Verified navigation, wrapping, state resets, invalid patterns, zero-length matches, match limits, scrolling, and focus preservation through DOM tests.

Verification used Node.js 24.20.0 because Node.js 22 specified in .nvmrc was unavailable through nvm.

AI assistance

Codex assisted with implementation, regression tests, and verification.

Type of change

  • Bug fix
  • New tool or feature
  • Tests
  • Refactor or cleanup
  • Docs

Checklist

  • I was assigned the linked issue
  • npm run lint && npm run test && npm run build passes locally
  • Logic changes live in lib/ and have a test in lib/__tests__/
  • For a bug fix: the new test fails without my change
  • No analytics, trackers, or calls that send user data off-device
  • Works in both light and dark themes (if UI changed)
  • Inputs have labels and it works with the keyboard alone (if UI changed)
  • New tool: registry entry, page.tsx, client component, opengraph-image.tsx, and the bug report dropdown are all done

Notes for reviewers

Changes are limited to app/(tools)/regex-tester/RegexTesterClient.tsx and app/(tools)/regex-tester/RegexTesterClient.test.tsx.

The implementation reuses the existing match collection and preserves the 1,000-match limit. DOM tests verify scroll targets and focus preservation. Browser visuals and screen-reader announcements were not manually tested.

All lint, test, build, and diff checks passed. No dependency or package-file changes were introduced.

@anurag629 anurag629 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hey @kachamsiddarth, this is really close. In the built app the wrap both ways, the "Match N of M" counter, Enter and Space on the buttons, zero-length matches like \b and the reset after an edit all work, and the active outline is easy to spot in both themes. Two things I ran into though:

  1. The page scrolls by itself. The scroll effect depends on [found, activeIndex], so it also runs on load and after every edit, not only on Previous or Next. On a 375x667 phone the page opens 127px down with the title scrolled off, and when the highlight box is below the fold the page jumps as soon as you stop typing.

  2. Match details and the Replace with box disappear on every keystroke in Pattern or Test text, because found is null while the input is pending. With three matches the page got about 460px shorter until the debounce ended, then grew back. On develop they just stay.

Something like this fixes both, and all 18 tests in your file still pass with it:

const [scrollRequest, setScrollRequest] = useState(0);

const found = results;
const matchCount = found?.matches.length ?? 0;
const canNavigate = !pending && matchCount > 0;
const activeIndex = canNavigate ? Math.min(activeMatchIndex, matchCount - 1) : -1;

useEffect(() => {
  if (scrollRequest > 0) activeMatchRef.current?.scrollIntoView({ block: "nearest", inline: "nearest" });
}, [scrollRequest]);

function goTo(step: number) {
  setActiveMatchIndex((activeIndex + step + matchCount) % matchCount);
  setScrollRequest((n) => n + 1);
}

Then disabled={!canNavigate} with onClick={() => goTo(-1)} and goTo(1) on the two buttons, and check pending first in the status text.

Could you add a test for each one too: scrollIntoView isn't called on mount or after an edit, only after a click, and "Match details" is still there right after a change to Test text.

@anurag629 anurag629 added the hacktoberfest-accepted PR counts for Hacktoberfest label Oct 30, 2026
@anurag629
anurag629 merged commit 1c731dc into codercops:develop Oct 30, 2026
3 checks passed
@anurag629

Copy link
Copy Markdown
Member

Hey @kachamsiddarth, thanks for all your PRs this month! If you haven't yet, come join our Discord (https://discord.gg/mpGdJyjaRQ) and run /link there to connect your GitHub. That gives you the Top Contributor role for your 5+ merged PRs, and your merges show up with your name in the shoutouts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hacktoberfest-accepted PR counts for Hacktoberfest

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regex Tester: add next/previous match navigation

2 participants