Skip to content

Commit d48b629

Browse files
committed
feat: optimize/speedup searching of files, setting robotcode.workspace.excludePatterns now supports gitignore like patterns
1 parent c654af5 commit d48b629

15 files changed

+73
-250
lines changed

.vscode/launch.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
// "Data.Tests.Versions.Rf61.a suite with a custom Name"
5454
// "Robotframework.Atest.Testdata.Variables",
5555
//"."
56-
"tags",
56+
"all",
57+
"--suite",
58+
"Data.Tests.Versions.Rf61",
5759
"."
5860
]
5961
},

package.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -679,12 +679,14 @@
679679
"robotcode.workspace.excludePatterns": {
680680
"type": "array",
681681
"default": [
682-
"**/.git/**",
683-
"**/node_modules/**",
684-
"**/.pytest_cache/**",
685-
"**/__pycache__/**",
686-
"**/.mypy_cache/**",
687-
"**/.robotcode_cache/**"
682+
"**/.git/",
683+
"**/.hatch/",
684+
"**/.venv/",
685+
"**/node_modules/",
686+
"**/.pytest_cache/",
687+
"**/__pycache__/",
688+
"**/.mypy_cache/",
689+
"**/.robotcode_cache/"
688690
],
689691
"items": {
690692
"type": "string"
@@ -1288,4 +1290,4 @@
12881290
"webpack": "^5.82.1",
12891291
"webpack-cli": "^5.1.1"
12901292
}
1291-
}
1293+
}

packages/core/src/robotcode/core/utils/glob_path.py

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@
33
import functools
44
import os
55
import re
6-
from pathlib import Path
7-
from typing import Any, Iterable, Iterator, Sequence, Union, cast
6+
from pathlib import Path, PurePath
7+
from typing import Any, Iterable, Iterator, Sequence, Tuple, Union, cast
88

99

10-
def _glob_pattern_to_re(pattern: str) -> str:
10+
def _glob_pattern_to_re(pattern: str) -> Tuple[str, bool]:
1111
result = "(?ms)^"
1212

1313
in_group = False
14+
only_dirs = False
1415

1516
i = 0
1617
while i < len(pattern):
1718
c = pattern[i]
18-
1919
if c in "\\/$^+.()=!|":
20-
result += "\\" + c
20+
if c == "/" and i == len(pattern) - 1:
21+
only_dirs = True
22+
else:
23+
result += "\\" + c
2124
elif c == "?":
2225
result += "."
2326
elif c in "[]":
@@ -59,23 +62,26 @@ def _glob_pattern_to_re(pattern: str) -> str:
5962

6063
result += "$"
6164

62-
return result
65+
return result, only_dirs
6366

6467

6568
@functools.lru_cache(maxsize=256)
66-
def _compile_glob_pattern(pattern: str) -> re.Pattern[str]:
67-
return re.compile(_glob_pattern_to_re(pattern))
69+
def _compile_glob_pattern(pattern: str) -> Tuple[re.Pattern[str], bool]:
70+
re_pattern, only_dirs = _glob_pattern_to_re(pattern)
71+
return re.compile(re_pattern), only_dirs
6872

6973

7074
class Pattern:
7175
def __init__(self, pattern: str) -> None:
7276
self.pattern = pattern
73-
self._re_pattern = _compile_glob_pattern(pattern)
77+
self._re_pattern, self.only_dirs = _compile_glob_pattern(pattern)
7478

75-
def matches(self, path: Union[Path, str, os.PathLike[Any]]) -> bool:
76-
if not isinstance(path, Path):
77-
path = Path(path)
78-
return self._re_pattern.fullmatch(str(path).replace(os.sep, "/")) is not None
79+
def matches(self, path: Union[PurePath, str, os.PathLike[str]]) -> bool:
80+
if isinstance(path, PurePath):
81+
path = path.as_posix()
82+
else:
83+
path = str(os.fspath(path))
84+
return self._re_pattern.fullmatch(path) is not None
7985

8086
def __str__(self) -> str:
8187
return self.pattern
@@ -84,15 +90,29 @@ def __repr__(self) -> str:
8490
return f"{type(self).__qualname__}(pattern={self.pattern!r}"
8591

8692

87-
def globmatches(pattern: str, path: Union[Path, str, os.PathLike[Any]]) -> bool:
93+
def globmatches(pattern: str, path: Union[PurePath, str, os.PathLike[Any]]) -> bool:
8894
return Pattern(pattern).matches(path)
8995

9096

97+
FILE_ATTRIBUTE_HIDDEN = 2
98+
99+
100+
def _is_hidden(entry: os.DirEntry[str]) -> bool:
101+
if entry.name.startswith("."):
102+
return True
103+
104+
if os.name == "nt" and (entry.stat().st_file_attributes & 2 != 0 or entry.name.startswith("$")):
105+
return True
106+
107+
return False
108+
109+
91110
def iter_files(
92111
path: Union[Path, str, os.PathLike[str]],
93112
patterns: Union[Sequence[Union[Pattern, str]], Pattern, str, None] = None,
94113
ignore_patterns: Union[Sequence[Union[Pattern, str]], Pattern, str, None] = None,
95114
*,
115+
include_hidden: bool = False,
96116
absolute: bool = False,
97117
_base_path: Union[Path, str, os.PathLike[str], None] = None,
98118
) -> Iterator[Path]:
@@ -108,24 +128,39 @@ def iter_files(
108128
if patterns is not None and isinstance(patterns, (str, Pattern)):
109129
patterns = [patterns]
110130
if patterns is not None:
111-
patterns = list(map(lambda p: p if isinstance(p, Pattern) else Pattern(p), patterns))
131+
patterns = [p if isinstance(p, Pattern) else Pattern(p) for p in patterns]
112132

113133
if ignore_patterns is not None and isinstance(ignore_patterns, (str, Pattern)):
114134
ignore_patterns = [ignore_patterns]
115135
if ignore_patterns is not None:
116-
ignore_patterns = list(map(lambda p: p if isinstance(p, Pattern) else Pattern(p), ignore_patterns))
136+
ignore_patterns = [p if isinstance(p, Pattern) else Pattern(p) for p in ignore_patterns]
117137

118138
try:
119-
for f in path.iterdir():
120-
if ignore_patterns is None or not any(
121-
p.matches(f.relative_to(_base_path)) for p in cast(Iterable[Pattern], ignore_patterns)
122-
):
123-
if f.is_dir():
124-
for e in iter_files(f, patterns, ignore_patterns, absolute=absolute, _base_path=_base_path):
125-
yield e
126-
elif patterns is None or any(
127-
p.matches(str(f.relative_to(_base_path))) for p in cast(Iterable[Pattern], patterns)
139+
with os.scandir(path) as it:
140+
for f in it:
141+
if not include_hidden and _is_hidden(f):
142+
continue
143+
144+
relative_path = path / f.name
145+
146+
if not ignore_patterns or not any(
147+
p.matches(relative_path) and (not p.only_dirs or p.only_dirs and f.is_dir())
148+
for p in cast(Iterable[Pattern], ignore_patterns)
128149
):
129-
yield f.absolute() if absolute else f
150+
if f.is_dir():
151+
yield from iter_files(
152+
f,
153+
patterns,
154+
ignore_patterns,
155+
include_hidden=include_hidden,
156+
absolute=absolute,
157+
_base_path=_base_path,
158+
)
159+
if not patterns or any(
160+
p.matches(relative_path) and (not p.only_dirs or p.only_dirs and f.is_dir())
161+
for p in cast(Iterable[Pattern], patterns)
162+
):
163+
yield Path(f).absolute() if absolute else Path(f)
164+
130165
except PermissionError:
131166
pass

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_references.test[references.robot-036-004-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_references.test[references.robot-036-005-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_references.test[references.robot-036-006-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_references.test[references.robot-036-004-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_references.test[references.robot-036-005-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_references.test[references.robot-036-006-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_references.test[references.robot-036-004-simple_keyword_call].out

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,6 @@ data: !GeneratedTestData
33
line: 36
44
name: simple keyword call
55
result:
6-
- !Location
7-
range:
8-
end:
9-
character: 7
10-
line: 2
11-
start:
12-
character: 4
13-
line: 2
14-
uri: discovery/.not_discovered.robot
15-
- !Location
16-
range:
17-
end:
18-
character: 7
19-
line: 5
20-
start:
21-
character: 4
22-
line: 5
23-
uri: discovery/.not_discovered.robot
246
- !Location
257
range:
268
end:

0 commit comments

Comments
 (0)