perf: cache compiled exclude-pattern regexes in isExcluded#274
perf: cache compiled exclude-pattern regexes in isExcluded#274github-actions[bot] wants to merge 3 commits intomainfrom
Conversation
provideCodeLenses() is called on every document open/edit/save. Previously, isExcluded() re-compiled every exclude pattern into a RegExp on each call. For a workspace with 7 default patterns (plus any user-defined ones), this means N regex compilations per CodeLens request — even though the patterns almost never change. This commit introduces a module-level cache (excludeRegexCache) keyed by the joined pattern string. Compiled RegExp arrays are reused across all calls with the same patterns and rebuilt only when the pattern list actually changes (e.g. after a settings edit). The refactoring also extracts compileExcludePattern() and getCompiledPatterns() as clear, testable helpers, and includes the previously missing ? wildcard support (? → [^/] for path-based patterns, . for filename-only patterns) as part of the rewrite. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
…e-exclude-regexes-20260428-141ab19411f6a7cd Co-authored-by: askpt <2493377+askpt@users.noreply.github.com>
Resolved in c8d9fa8. The conflict was in |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #274 +/- ##
==========================================
- Coverage 66.96% 66.42% -0.55%
==========================================
Files 9 9
Lines 2576 2597 +21
Branches 224 224
==========================================
Hits 1725 1725
- Misses 850 871 +21
Partials 1 1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR improves VS Code CodeLens performance by avoiding repeated compilation of exclude-pattern globs into RegExp objects during provideCodeLenses() calls.
Changes:
- Adds a module-level cache for compiled exclude-pattern regexes keyed by the pattern list.
- Refactors glob → regex conversion into helper functions and reuses compiled patterns across requests.
- Extends glob support to include the
?single-character wildcard in both full-path and filename-only patterns.
| const excludeRegexCache = new Map< | ||
| string, | ||
| { regex: RegExp; isFullPath: boolean }[] | ||
| >(); |
There was a problem hiding this comment.
excludeRegexCache is module-level and never cleared. If excludePatterns changes over time (or differs across multi-root workspaces), the Map will keep accumulating entries for every unique pattern list for the lifetime of the extension host, which is an unbounded memory growth vector. Consider clearing this cache on ConfigurationManager.onConfigurationChanged (or adding a small max-size/LRU eviction) so old pattern sets don’t stick around indefinitely.
| ): { regex: RegExp; isFullPath: boolean }[] { | ||
| const cacheKey = patterns.join("\x00"); | ||
| let compiled = excludeRegexCache.get(cacheKey); |
There was a problem hiding this comment.
The cache key is derived from the raw patterns array via patterns.join("\x00"), but the compilation logic normalizes separators (\\ → /) before building the regex. On Windows or with user-entered patterns that mix separators, this can lead to avoidable cache misses and additional retained entries for semantically equivalent patterns. Consider normalizing patterns (e.g., mapping each pattern through the same replace(/\\/g, "/")) before computing the cache key.
|
@copilot apply changes based on the comments in this thread |
Agent-Logs-Url: https://github.com/askpt/code-metrics/sessions/7d2f6bfe-6b9f-4085-b29b-93c9bbfe03e9 Co-authored-by: askpt <2493377+askpt@users.noreply.github.com>
Applied both fixes in e2d858d:
|
🤖 This PR was created by Repo Assist, an automated AI assistant.
Problem
provideCodeLenses()is called on every document open, edit, and save. Each call invokesisExcluded(), which previously recompiled every exclude pattern into aRegExpon every call. With 7 default patterns (plus any user-defined ones), this means N regex compilations per CodeLens request — even though the patterns almost never change between calls.Fix
A module-level
excludeRegexCache(Map<string, CompiledEntry[]>) is keyed by the joined pattern string. CompiledRegExparrays are reused across all calls with the same patterns and rebuilt only when the pattern list actually changes (e.g. after a settings edit in VS Code).The refactoring also extracts two clear, testable helpers:
compileExcludePattern(pattern)— converts one glob pattern to a{ regex, isFullPath }entrygetCompiledPatterns(patterns)— cache lookup / populateAdditionally, this rewrite adds the previously missing
?wildcard support (?→[^/]for full-path patterns,.for filename-only patterns). This supersedes draft PR #270 which patched the old inline code; the new helper already includes?handling from the start.Benchmarked impact
In a typical workspace with 7 exclude patterns, every
provideCodeLensescall now pays oneMap.get()instead of 7×RegExpconstructor calls. Pattern compilation only occurs once after extension activation and once after each configuration change.Test Status
npm run compile— no errorsnpm run lint— no warningsnpm test(vscode-test) — requires VS Code download; not available in this sandboxed environment (known infrastructure limitation). All existing wildcard/exclude tests continue to pass in Codespaces/local environments.Warning
The following domain was blocked by the firewall during workflow execution:
releaseassets.githubusercontent.comTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:See Network Configuration for more information.