Skip to content

feat(rules): add URL match types and drag-to-reorder priority#26

Merged
BlackHole1 merged 2 commits into
mainfrom
feat/url-rules
Jun 16, 2026
Merged

feat(rules): add URL match types and drag-to-reorder priority#26
BlackHole1 merged 2 commits into
mainfrom
feat/url-rules

Conversation

@BlackHole1

Copy link
Copy Markdown
Member

Per-URL rules (enhanced mode) gain a match type — domain suffix, exact domain, domain keyword, or a regular expression over the full URL — and a user-arranged priority order: rules resolve top to bottom, first match wins, and the list is drag-reorderable. The URL-scheme API, .lockime backup/import, and the localized docs carry the new field through.

A rule's pattern is its portable identity (backups and import key on it), so the mutators enforce that no two rules ever share one: the upsert/reorder logic is centralized in URLRuleList, and the editor and URL-scheme API reject a colliding pattern. An edit can no longer silently mint a duplicate that would collapse, losing a rule, on the next export/import. URL-regex matching is bounded in UTF-16 code units to cap the regex engine's backtracking on long inputs.

Per-URL rules (enhanced mode) gain a match type — domain suffix,
exact domain, domain keyword, or a regular expression over the full
URL — and a user-arranged priority order: rules resolve top to
bottom, first match wins, and the list is drag-reorderable. The
URL-scheme API, .lockime backup/import, and the localized docs carry
the new field through.

A rule's pattern is its portable identity (backups and import key on
it), so the mutators enforce that no two rules ever share one: the
upsert/reorder logic is centralized in URLRuleList, and the editor
and URL-scheme API reject a colliding pattern. An edit can no longer
silently mint a duplicate that would collapse, losing a rule, on the
next export/import. URL-regex matching is bounded in UTF-16 code
units to cap the regex engine's backtracking on long inputs.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ae6f4d0d-8bcf-44c2-bf98-960c8f5b9b5a

📥 Commits

Reviewing files that changed from the base of the PR and between 8792469 and 1836caa.

📒 Files selected for processing (12)
  • Sources/LockIMEKit/Rules/URLRuleList.swift
  • Tests/LockIMEKitTests/LocalizationGuardTests.swift
  • Tests/LockIMEKitTests/URLRuleListTests.swift
  • docs/URL-Scheme-API/README.de.md
  • docs/URL-Scheme-API/README.es.md
  • docs/URL-Scheme-API/README.fr.md
  • docs/URL-Scheme-API/README.ja.md
  • docs/URL-Scheme-API/README.md
  • docs/URL-Scheme-API/README.pt.md
  • docs/URL-Scheme-API/README.ru.md
  • docs/URL-Scheme-API/README.zh-CN.md
  • docs/URL-Scheme-API/README.zh-TW.md
✅ Files skipped from review due to trivial changes (3)
  • docs/URL-Scheme-API/README.ja.md
  • docs/URL-Scheme-API/README.zh-TW.md
  • docs/URL-Scheme-API/README.es.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • Tests/LockIMEKitTests/URLRuleListTests.swift
  • Sources/LockIMEKit/Rules/URLRuleList.swift
  • docs/URL-Scheme-API/README.ru.md
  • docs/URL-Scheme-API/README.zh-CN.md

Summary by CodeRabbit

Release Notes

  • New Features

    • Added enhanced per-URL rules with selectable match types (domain/subdomains, exact domain, keyword, full-URL regex) and first-match priority.
    • Added drag-and-drop URL rule reordering with preserved priority.
    • Updated the URL rule editor to use a sheet-based flow with match-type selection.
    • Improved merge imports to retain/review URL rule priority order.
  • Bug Fixes

    • Added stricter validation for rule pattern updates and provided match-type details when listing rules.
  • Documentation

    • Updated README and URL Scheme API docs to reflect matchType.
  • Tests

    • Expanded coverage for match types, ordering, imports, and localization.

Walkthrough

This PR adds flexible URL matching to LockIME's enhanced mode. A new URLMatchType enum (domainSuffix, domain, domainKeyword, urlRegex) is introduced in LockConfiguration, and URLRule gains a matchType field with backward-compatible lenient Codable decoding. A new URLRuleList utility enforces case-insensitive pattern uniqueness and slot-preserving upsert/reorder operations.

URLMatcher is refactored from host-only matching to URL-string dispatch by match type, including bounded NSRegularExpression for urlRegex rules. LockEngine is updated to key deduplication on the matched rule pattern. URLCommand.setURLRule gains matchType, the parser accepts a pattern alias and validates regex at parse time, and URLCommandHandler adds host-collision detection.

ConfigBackup and ImportPlan are extended to persist matchType, detect URL-order differences, and resolve URL priority under merge vs. replace. AppState delegates to URLRuleList and gains reorderURLRules. The settings pane is rebuilt with a sheet-based URLRuleEditor, drag-and-drop row reordering, and match-type pickers. All sheets gain locale re-injection. Localization strings, README features bullets, and URL Scheme API docs are updated across all supported languages.

Possibly Related PRs

  • oomol-lab/LockIME#22: Introduced one-shot .switchOnce actions for URL rules; this PR changes the SwitchKey context from matched host to matched rule pattern, directly extending that deduplication mechanism.
  • oomol-lab/LockIME#25: Introduced the lockime:// URL Scheme API including the original set-url-rule command; this PR extends that command with matchType parsing, validation, and persistence.
  • oomol-lab/LockIME#18: Modified the backup/import pipeline for URL rules; this PR extends that pipeline to carry matchType metadata and resolve URL-rule ordering under merge vs. replace.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format and clearly describes the main changes: adding URL match types and drag-to-reorder functionality to per-URL rules.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about URL match types, priority ordering, pattern identity enforcement, and regex matching bounds.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/url-rules

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

124-126: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the stray + before xcbeautify.

That character will render literally in the published README.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 124 - 126, Remove the stray `+` character that
appears before the `[xcbeautify]` link in the installation instructions. This
character should not be present and will render literally in the published
README, disrupting the formatting of the dependency list.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/URL-Scheme-API/README.zh-CN.md`:
- Around line 142-145: The documentation lists only a partial set of match-type
aliases (suffix, keyword, regex) without clarifying whether this is a complete
or example list, creating ambiguity about other valid aliases. In
docs/URL-Scheme-API/README.zh-CN.md at lines 142-145, update the match-type
alias sentence to either enumerate all supported aliases (domain-exact, exact,
domainkeyword, domainsuffix, urlregex, matchtype) or explicitly state that the
listed aliases are examples only and the parser accepts additional forms. Then
apply the identical clarification to docs/URL-Scheme-API/README.zh-TW.md at
lines 143-145 to maintain consistency across the Simplified and Traditional
Chinese versions.

In `@Sources/LockIMEKit/Backup/ImportPlan.swift`:
- Around line 255-260: The ImportPlan file keys URL rules by raw case-sensitive
hostPattern strings at multiple locations, which can miss pattern collisions
differing only by case and break conflict detection. Create a canonical
pattern-key function (such as normalizing hostPattern to lowercase) and apply
this consistently everywhere URL rules are keyed: in the localByHost Dictionary
construction (line 258), in the seenFileHosts set insertion (line 259), and at
all other affected locations mentioned in the consolidated sites (lines 289-291,
367-373, 403-411). Ensure the same canonical normalization is used throughout
the file for all hostPattern-based lookups and deduplication.

In `@Sources/LockIMEKit/Rules/URLRuleList.swift`:
- Around line 77-80: The guard statement in the URLRuleList method is checking
only set equality of IDs, which allows duplicate IDs in the ordered array to
pass validation. To enforce that reordered accepts only valid permutations with
no duplicates, add an additional condition to the guard that verifies the
ordered array's ID count equals the count of unique IDs. This ensures that an
input like [a, a, b] is rejected rather than returning duplicated rules. Check
that ordered.map(\.id).count equals Set(ordered.map(\.id)).count or equivalently
that the ordered array length equals the byID keys count.

In `@Tests/LockIMEKitTests/LocalizationGuardTests.swift`:
- Around line 213-216: The check in the LocalizationGuardTests.swift file at the
Issue.record call is too lenient because it only searches for the presence of
`.environment(\.locale` without verifying that `state.locale` specifically is
the injected value. Update the condition in the if statement to check for the
complete pattern `.environment(\.locale, state.locale)` instead of just
`.environment(\.locale` to ensure sheets are re-injecting the correct locale
override as required by the in-app language override contract.

---

Outside diff comments:
In `@README.md`:
- Around line 124-126: Remove the stray `+` character that appears before the
`[xcbeautify]` link in the installation instructions. This character should not
be present and will render literally in the published README, disrupting the
formatting of the dependency list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0dbd2dff-2db4-4882-8011-8b1e9d24d20d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f77e8f and 8792469.

📒 Files selected for processing (39)
  • README.md
  • Sources/LockIME/API/URLCommandHandler.swift
  • Sources/LockIME/AppState.swift
  • Sources/LockIME/Localizable.xcstrings
  • Sources/LockIME/UI/AboutView.swift
  • Sources/LockIME/UI/Settings/AppRulesSettingsPane.swift
  • Sources/LockIME/UI/Settings/ImportReviewSheet.swift
  • Sources/LockIME/UI/Settings/URLRulesSettingsPane.swift
  • Sources/LockIMEKit/API/URLCommand.swift
  • Sources/LockIMEKit/Backup/ConfigBackup.swift
  • Sources/LockIMEKit/Backup/ImportPlan.swift
  • Sources/LockIMEKit/Enhanced/URLMatcher.swift
  • Sources/LockIMEKit/LockEngine/LockEngine.swift
  • Sources/LockIMEKit/Rules/LockConfiguration.swift
  • Sources/LockIMEKit/Rules/URLRuleList.swift
  • Tests/LockIMEKitTests/ConfigBackupTests.swift
  • Tests/LockIMEKitTests/ImportPlanTests.swift
  • Tests/LockIMEKitTests/LocalizationGuardTests.swift
  • Tests/LockIMEKitTests/LockConfigurationTests.swift
  • Tests/LockIMEKitTests/URLCommandParserTests.swift
  • Tests/LockIMEKitTests/URLMatcherTests.swift
  • Tests/LockIMEKitTests/URLRuleListTests.swift
  • docs/README/README.de.md
  • docs/README/README.es.md
  • docs/README/README.fr.md
  • docs/README/README.ja.md
  • docs/README/README.pt.md
  • docs/README/README.ru.md
  • docs/README/README.zh-CN.md
  • docs/README/README.zh-TW.md
  • docs/URL-Scheme-API/README.de.md
  • docs/URL-Scheme-API/README.es.md
  • docs/URL-Scheme-API/README.fr.md
  • docs/URL-Scheme-API/README.ja.md
  • docs/URL-Scheme-API/README.md
  • docs/URL-Scheme-API/README.pt.md
  • docs/URL-Scheme-API/README.ru.md
  • docs/URL-Scheme-API/README.zh-CN.md
  • docs/URL-Scheme-API/README.zh-TW.md

Comment thread docs/URL-Scheme-API/README.zh-CN.md Outdated
Comment thread Sources/LockIMEKit/Backup/ImportPlan.swift
Comment thread Sources/LockIMEKit/Rules/URLRuleList.swift Outdated
Comment thread Tests/LockIMEKitTests/LocalizationGuardTests.swift Outdated
Address CodeRabbit review on #26:

- URLRuleList.reordered: reject non-permutations carrying duplicate ids
  (matching id set but wrong count, e.g. [a, a, b] against [a, b]); set
  equality alone let such input through and returned a list with a
  duplicated rule, corrupting the persisted priority order.
- LocalizationGuardTests: tighten the .sheet locale guard to require the
  window re-inject the app's own locale (state/appState.locale), not just
  any \.locale value, and strip per-line comments so a commented-out
  modifier can't satisfy it.
- URL-Scheme-API docs (all languages): mark the match-type alias list as
  non-exhaustive, since the parser accepts more aliases (domain-exact,
  exact, domainsuffix, domainkeyword, urlregex, matchtype) than were
  listed. English authoritative copy and every translation kept in sync.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@BlackHole1 BlackHole1 merged commit d37e950 into main Jun 16, 2026
3 checks passed
@BlackHole1 BlackHole1 deleted the feat/url-rules branch June 16, 2026 22:56
BlackHole1 added a commit that referenced this pull request Jun 17, 2026
The committed screenshots predated the URL match-type badges and
drag-to-reorder priority (#26) and the General "Automation" section
(#25), so all three panes were out of date. Regenerate the full set
of 12 (General, App Rules, URL Rules x en/zh-CN x light/dark).

The URL Rules pane now shows four rules spanning every match type
(domain suffix, exact domain, domain keyword, URL regex) to surface
the new badges and the reorder caption. Images are now 2024x1600
because SettingsRootView gained a 600pt minimum content height.

Signed-off-by: Kevin Cui <bh@bugs.cc>
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