mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 14:16:21 +00:00
fix(util): ensure bare * and ? in non-** glob patterns do not match / (#1732)
This commit is contained in:
1 parent
ac256f3630
commit
70d32f2453
3 files changed
+47
-2
No files matched your search
@@ -6,6 +6,7 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
- Add Grok Build support (context `grok`, setup CLI, hooks)
|
||||
- The `languages` key in project configurations was changed to `language_servers` to better reflect
|
||||
the actual semantics (configurations are automatically migrated)
|
||||
- Fix: `glob_match` bare `*` and `?` in non-`**` patterns matched across `/`, contradicting its documented behavior #1732
|
||||
|
||||
* Language Servers:
|
||||
- Allow language server priorities to be configured in `serena_config.yml` (for auto-detection during
|
||||
|
||||
@@ -5,6 +5,7 @@ import re
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
from enum import StrEnum
|
||||
from functools import lru_cache
|
||||
from typing import Any, Literal, Self
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
@@ -240,6 +241,43 @@ def expand_braces(pattern: str) -> list[str]:
|
||||
return patterns
|
||||
|
||||
|
||||
@lru_cache(maxsize=256)
|
||||
def _translate_glob_no_double_star(pattern: str) -> str:
|
||||
res = []
|
||||
i = 0
|
||||
n = len(pattern)
|
||||
while i < n:
|
||||
c = pattern[i]
|
||||
i += 1
|
||||
if c == "*":
|
||||
if not res or res[-1] != "[^/]*":
|
||||
res.append("[^/]*")
|
||||
elif c == "?":
|
||||
res.append("[^/]")
|
||||
elif c == "[":
|
||||
j = i
|
||||
if j < n and pattern[j] == "!":
|
||||
j += 1
|
||||
if j < n and pattern[j] == "]":
|
||||
j += 1
|
||||
while j < n and pattern[j] != "]":
|
||||
j += 1
|
||||
if j >= n:
|
||||
res.append(r"\[")
|
||||
else:
|
||||
stuff = pattern[i:j]
|
||||
if stuff.startswith("!"):
|
||||
stuff = "^" + stuff[1:]
|
||||
elif stuff.startswith("^"):
|
||||
stuff = r"\^" + stuff
|
||||
res.append(f"[{stuff}]")
|
||||
i = j + 1
|
||||
else:
|
||||
res.append(re.escape(c))
|
||||
inner = "".join(res)
|
||||
return f"(?s:{inner})\\Z"
|
||||
|
||||
|
||||
def glob_match(pattern: str, path: str) -> bool:
|
||||
"""
|
||||
Match a file path against a glob pattern.
|
||||
@@ -289,8 +327,8 @@ def glob_match(pattern: str, path: str) -> bool:
|
||||
|
||||
return False
|
||||
else:
|
||||
# Simple pattern without **, use fnmatch directly
|
||||
return fnmatch.fnmatch(path, pattern)
|
||||
# Simple pattern without **, translate bare * and ? to not match /
|
||||
return bool(re.match(_translate_glob_no_double_star(pattern), path))
|
||||
|
||||
|
||||
class GlobMatcher:
|
||||
|
||||
@@ -593,10 +593,16 @@ class TestGlobMatch:
|
||||
[
|
||||
# Basic wildcard patterns
|
||||
("*.py", "file.py", True),
|
||||
("*.py", "src/file.py", False),
|
||||
("*.py", "file.txt", False),
|
||||
("*agent.py", "agent.py", True),
|
||||
("*agent.py", "process_isolated_agent.py", True),
|
||||
("*agent.py", "src/agent.py", False),
|
||||
("*agent.py", "agent_test.py", False),
|
||||
("a?b.py", "acb.py", True),
|
||||
("a?b.py", "a/b.py", False),
|
||||
("src/*.py", "src/file.py", True),
|
||||
("src/*.py", "src/sub/file.py", False),
|
||||
# Double asterisk patterns
|
||||
("**agent.py", "agent.py", True),
|
||||
("**agent.py", "src/agent.py", True),
|
||||
|
||||
Reference in new issue
Block a user