pseek 3.6.0__tar.gz → 3.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pseek
3
- Version: 3.6.0
3
+ Version: 3.6.2
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -62,6 +62,7 @@ Fast and powerful command-line search tool for finding files, directories, and t
62
62
  * [Case Sensitive](#case-sensitive)
63
63
  * [Whole Word](#whole-word)
64
64
  * [Fuzzy](#fuzzy)
65
+ * [Full Path](#full-path-1)
65
66
  * [Combined Prefixes](#combined-prefixes)
66
67
  * [Automatic Filtering](#automatic-filtering)
67
68
  * [Manual Filtering](#manual-filtering)
@@ -100,17 +101,19 @@ Fast and powerful command-line search tool for finding files, directories, and t
100
101
  * Search file names
101
102
  * Search directory names
102
103
  * Search file contents
103
- * Search inside archive files
104
104
  * Boolean query expressions (`and`, `or`, `not`)
105
105
  * Regular expressions
106
106
  * Fuzzy matching
107
107
  * Whole-word matching
108
108
  * Case-sensitive search
109
+ * Search inside archive files
109
110
  * Archive recursion depth control
110
111
  * Extension filters
111
112
  * Path filters
112
113
  * Size filtering
113
- * Full path output
114
+ * Depth filtering
115
+ * Automatic filtering (Supports git rules)
116
+ * Parallel search
114
117
  * Highlight matches in output
115
118
  * Cross-platform (Linux, macOS, Windows)
116
119
 
@@ -173,7 +176,7 @@ simultaneously.
173
176
  To search for a query that starts with `-`, use `--` to mark the end of options:
174
177
 
175
178
  ```bash
176
- psk -- --path
179
+ psk -- --path # The query is "--path"
177
180
  ```
178
181
 
179
182
  Of course the search query is optional. When no query is provided, Pseek displays the files and directories and file contents within the selected scope.
@@ -289,7 +292,7 @@ Example:
289
292
  psk "hello world"
290
293
  ```
291
294
 
292
- > **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
295
+ > **Note:** To use case-sensitive, whole-word matching, regular expression search, fuzzy search, and full path search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
293
296
 
294
297
  ### Case Sensitive Search
295
298
 
@@ -316,11 +319,13 @@ Does not match: `cats`, `concatenate`
316
319
  Enable regex mode:
317
320
 
318
321
  ```bash
319
- psk error\d+ --regex
322
+ psk "error\d+" --regex
320
323
  ```
321
324
 
322
325
  Example matches: `error1`, `error25`, `error999`
323
326
 
327
+ > **Note:** Regex matching and whole word matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `psk "\berror\d+\b" --regex`
328
+
324
329
  ### Fuzzy Search
325
330
 
326
331
  Fuzzy search allows approximate matching.
@@ -444,6 +449,8 @@ Used for grouping expressions.
444
449
 
445
450
  Each term can have its own search mode.
446
451
 
452
+ > **Note:** For more detailed information about the modes, please refer to the [query modes](#query-modes) section.
453
+
447
454
  #### Regex
448
455
 
449
456
  ```text
@@ -492,6 +499,18 @@ Example:
492
499
  psk 'f"apple"' --expr
493
500
  ```
494
501
 
502
+ #### Full Path
503
+
504
+ ```text
505
+ p"text"
506
+ ```
507
+
508
+ Example:
509
+
510
+ ```bash
511
+ psk 'p"lib"' --expr
512
+ ```
513
+
495
514
  #### Combined Prefixes
496
515
 
497
516
  Prefixes can be combined.
@@ -502,6 +521,7 @@ Examples:
502
521
  rc"text"
503
522
  cw"text"
504
523
  cf"text"
524
+ pc"text"
505
525
  wcf"text"
506
526
  ```
507
527
 
@@ -518,7 +538,9 @@ Meaning:
518
538
 
519
539
  simultaneously.
520
540
 
521
- Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
541
+ Allowed modes: `r`, `c`, `w`, `f`, `p`, `rp`, `pc`, `wp`, `fp`, `rc`, `cw`, `cf`, `wf`, `cwf`, `rcp`, `cwp`, `cfp`, `wfp`, `cwfp`
542
+
543
+ and their permutations.
522
544
 
523
545
  > **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
524
546
 
@@ -34,6 +34,7 @@ Fast and powerful command-line search tool for finding files, directories, and t
34
34
  * [Case Sensitive](#case-sensitive)
35
35
  * [Whole Word](#whole-word)
36
36
  * [Fuzzy](#fuzzy)
37
+ * [Full Path](#full-path-1)
37
38
  * [Combined Prefixes](#combined-prefixes)
38
39
  * [Automatic Filtering](#automatic-filtering)
39
40
  * [Manual Filtering](#manual-filtering)
@@ -72,17 +73,19 @@ Fast and powerful command-line search tool for finding files, directories, and t
72
73
  * Search file names
73
74
  * Search directory names
74
75
  * Search file contents
75
- * Search inside archive files
76
76
  * Boolean query expressions (`and`, `or`, `not`)
77
77
  * Regular expressions
78
78
  * Fuzzy matching
79
79
  * Whole-word matching
80
80
  * Case-sensitive search
81
+ * Search inside archive files
81
82
  * Archive recursion depth control
82
83
  * Extension filters
83
84
  * Path filters
84
85
  * Size filtering
85
- * Full path output
86
+ * Depth filtering
87
+ * Automatic filtering (Supports git rules)
88
+ * Parallel search
86
89
  * Highlight matches in output
87
90
  * Cross-platform (Linux, macOS, Windows)
88
91
 
@@ -145,7 +148,7 @@ simultaneously.
145
148
  To search for a query that starts with `-`, use `--` to mark the end of options:
146
149
 
147
150
  ```bash
148
- psk -- --path
151
+ psk -- --path # The query is "--path"
149
152
  ```
150
153
 
151
154
  Of course the search query is optional. When no query is provided, Pseek displays the files and directories and file contents within the selected scope.
@@ -261,7 +264,7 @@ Example:
261
264
  psk "hello world"
262
265
  ```
263
266
 
264
- > **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
267
+ > **Note:** To use case-sensitive, whole-word matching, regular expression search, fuzzy search, and full path search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
265
268
 
266
269
  ### Case Sensitive Search
267
270
 
@@ -288,11 +291,13 @@ Does not match: `cats`, `concatenate`
288
291
  Enable regex mode:
289
292
 
290
293
  ```bash
291
- psk error\d+ --regex
294
+ psk "error\d+" --regex
292
295
  ```
293
296
 
294
297
  Example matches: `error1`, `error25`, `error999`
295
298
 
299
+ > **Note:** Regex matching and whole word matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `psk "\berror\d+\b" --regex`
300
+
296
301
  ### Fuzzy Search
297
302
 
298
303
  Fuzzy search allows approximate matching.
@@ -416,6 +421,8 @@ Used for grouping expressions.
416
421
 
417
422
  Each term can have its own search mode.
418
423
 
424
+ > **Note:** For more detailed information about the modes, please refer to the [query modes](#query-modes) section.
425
+
419
426
  #### Regex
420
427
 
421
428
  ```text
@@ -464,6 +471,18 @@ Example:
464
471
  psk 'f"apple"' --expr
465
472
  ```
466
473
 
474
+ #### Full Path
475
+
476
+ ```text
477
+ p"text"
478
+ ```
479
+
480
+ Example:
481
+
482
+ ```bash
483
+ psk 'p"lib"' --expr
484
+ ```
485
+
467
486
  #### Combined Prefixes
468
487
 
469
488
  Prefixes can be combined.
@@ -474,6 +493,7 @@ Examples:
474
493
  rc"text"
475
494
  cw"text"
476
495
  cf"text"
496
+ pc"text"
477
497
  wcf"text"
478
498
  ```
479
499
 
@@ -490,7 +510,9 @@ Meaning:
490
510
 
491
511
  simultaneously.
492
512
 
493
- Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
513
+ Allowed modes: `r`, `c`, `w`, `f`, `p`, `rp`, `pc`, `wp`, `fp`, `rc`, `cw`, `cf`, `wf`, `cwf`, `rcp`, `cwp`, `cfp`, `wfp`, `cwfp`
514
+
515
+ and their permutations.
494
516
 
495
517
  > **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
496
518
 
@@ -30,22 +30,16 @@ def get_archive_path_size(info, file_type: str) -> int:
30
30
  def archive_should_skip(path_info: Path, config, p_size: float, file_ext, is_dir=False):
31
31
  """Check whether the file/directory inside archive files should be skipped based on various filters"""
32
32
 
33
- if (config.arc_include and not any(path_info.is_relative_to(inc) for inc in config.arc_include)) \
33
+ path_info_str = str(path_info)
34
+ return (config.arc_include and not any(path_info.is_relative_to(inc) for inc in config.arc_include)) \
34
35
  or (config.arc_exclude and any(path_info.is_relative_to(exc) for exc in config.arc_exclude)) \
35
36
  or (config.arc_ext and file_ext not in config.arc_ext) \
36
37
  or (config.arc_exc_ext and file_ext in config.arc_exc_ext) \
37
38
  or (config.arc_size and (is_dir or not any(
38
39
  minimum <= p_size <= maximum
39
40
  for minimum, maximum in config.arc_size
40
- ))):
41
- return True
42
-
43
- if config.re_include:
44
- return not config.re_include.search(str(path_info))
45
- if config.re_exclude:
46
- return config.re_exclude.search(str(path_info)) is not None
47
-
48
- return False
41
+ ))) or (config.re_include and not config.re_include.search(path_info_str)) \
42
+ or (config.re_exclude and config.re_exclude.search(path_info_str) is not None)
49
43
 
50
44
 
51
45
  def extract_names_from_archive(file_path: Path, config, depth: int = -1,
@@ -78,8 +72,8 @@ def extract_names_from_archive(file_path: Path, config, depth: int = -1,
78
72
  with opener(file_stream) as f:
79
73
  for info in f.infolist():
80
74
  name = Path(info.filename)
81
- new_path_ext = get_path_suffix(name)
82
75
  is_dir = info.is_dir()
76
+ new_path_ext = get_path_suffix(name, is_dir)
83
77
 
84
78
  if not archive_should_skip(
85
79
  name,
@@ -105,8 +99,8 @@ def extract_names_from_archive(file_path: Path, config, depth: int = -1,
105
99
  with py7zr.SevenZipFile(file_stream, mode='r') as z:
106
100
  for info in z.list():
107
101
  name = Path(info.filename)
108
- new_path_ext = get_path_suffix(name)
109
102
  is_dir = info.is_directory
103
+ new_path_ext = get_path_suffix(name, is_dir)
110
104
 
111
105
  if not archive_should_skip(
112
106
  name,
@@ -143,8 +137,8 @@ def extract_names_from_archive(file_path: Path, config, depth: int = -1,
143
137
  with tarfile.open(fileobj=file_stream, mode=mode) as tf:
144
138
  for member in tf.getmembers():
145
139
  name = Path(member.name)
146
- new_path_ext = get_path_suffix(name)
147
140
  is_dir = member.isdir()
141
+ new_path_ext = get_path_suffix(name, is_dir)
148
142
 
149
143
  if not archive_should_skip(
150
144
  name,
@@ -203,10 +197,10 @@ def extract_text_from_archive(file_path: Path, config, depth: int = -1,
203
197
  for info in f.infolist():
204
198
  if info.is_dir():
205
199
  continue
206
-
200
+
207
201
  file_name = Path(info.filename)
208
202
  new_path_ext = get_path_suffix(file_name)
209
-
203
+
210
204
  if archive_should_skip(
211
205
  file_name,
212
206
  config,
@@ -243,7 +237,7 @@ def extract_text_from_archive(file_path: Path, config, depth: int = -1,
243
237
 
244
238
  file_name = Path(info.filename)
245
239
  new_path_ext = get_path_suffix(file_name)
246
-
240
+
247
241
  if archive_should_skip(
248
242
  file_name,
249
243
  config,
@@ -282,7 +276,7 @@ def extract_text_from_archive(file_path: Path, config, depth: int = -1,
282
276
 
283
277
  file_name = Path(member.name)
284
278
  new_path_ext = get_path_suffix(file_name)
285
-
279
+
286
280
  if archive_should_skip(
287
281
  file_name,
288
282
  config,
@@ -1,5 +1,7 @@
1
1
  import json
2
2
  import re
3
+ from itertools import permutations
4
+ from pathlib import Path
3
5
 
4
6
  import click
5
7
  from lark import Lark, Transformer
@@ -16,7 +18,16 @@ class ExprNode:
16
18
 
17
19
  class TermNode(ExprNode):
18
20
  """Node representing a single search term"""
19
- def __init__(self, term: str, regex, whole_word, case_sensitive, fuzzy, fuzzy_level):
21
+ def __init__(
22
+ self,
23
+ term: str,
24
+ regex: bool,
25
+ whole_word: bool,
26
+ case_sensitive: bool,
27
+ fuzzy: bool,
28
+ fuzzy_level: int | None,
29
+ full_path: bool
30
+ ):
20
31
  self.raw_term = term
21
32
  self.term_lower = term.lower()
22
33
  self.regex = regex
@@ -24,6 +35,7 @@ class TermNode(ExprNode):
24
35
  self.case_sensitive = case_sensitive
25
36
  self.fuzzy = fuzzy
26
37
  self.fuzzy_level = fuzzy_level
38
+ self.full_path = full_path
27
39
 
28
40
  if not fuzzy:
29
41
  flags = 0 if case_sensitive else re.IGNORECASE # Adjust case sensitivity
@@ -37,7 +49,10 @@ class TermNode(ExprNode):
37
49
 
38
50
  self.pattern = compile_regex(term, flags) # Precompile the regex pattern for performance
39
51
 
40
- def evaluate(self, text: str) -> bool:
52
+ def evaluate(self, text: str | Path) -> bool:
53
+ if isinstance(text, Path):
54
+ text = text.name if not self.full_path else str(text)
55
+
41
56
  # Fuzzy search mode
42
57
  text_cmp = text if self.case_sensitive else text.lower()
43
58
  term = self.raw_term if self.case_sensitive else self.term_lower
@@ -114,8 +129,25 @@ class OrNode(ExprNode):
114
129
  return self.left.evaluate(text) or self.right.evaluate(text)
115
130
 
116
131
 
132
+ def gvp() -> str:
133
+ """Generate all possible states and permutations of input prefixes
134
+
135
+ Returns:
136
+ str: prefixes=("f", "r", "rf") -> result="f|r|rf|fr"
137
+ """
138
+
139
+ prefixes = {'r','c','w','f','p','rp','pc','wp','fp','rc','cw',
140
+ 'cf','wf','cwf','rcp','cwp','cfp','wfp','cwfp'}
141
+ valid_prefixes = set()
142
+
143
+ for p in prefixes:
144
+ valid_prefixes |= {''.join(pr) for pr in permutations(p)}
145
+
146
+ return '|'.join(valid_prefixes)
147
+
148
+
117
149
  # Lark grammar for parsing logical expressions
118
- query_grammar = r"""
150
+ query_grammar = rf"""
119
151
  ?start: expr
120
152
 
121
153
  ?expr: or_expr
@@ -133,7 +165,7 @@ query_grammar = r"""
133
165
  | ESCAPED_STRING -> string
134
166
  | "(" expr ")"
135
167
 
136
- PREFIXED_STRING: /(r|c|w|f|rc|cr|cw|wc|cf|fc|wf|fw|cwf|cfw|wcf|wfc|fcw|fwc)"([^"\\]|\\.)*"/
168
+ PREFIXED_STRING: /({gvp()})"([^"\\]|\\.)*"/
137
169
 
138
170
  %import common.ESCAPED_STRING
139
171
  %import common.WS
@@ -171,7 +203,8 @@ class TreeToExpr(Transformer):
171
203
  False,
172
204
  False,
173
205
  False,
174
- None
206
+ None,
207
+ False
175
208
  )
176
209
 
177
210
  def prefixed_string(self, s):
@@ -179,7 +212,7 @@ class TreeToExpr(Transformer):
179
212
  text = str(s[0]) # e.g., 'rc"pattern"'
180
213
 
181
214
  quote_index = text.index('"')
182
- prefix = text[:quote_index].lower()
215
+ prefix = text[:quote_index]
183
216
  quoted = text[quote_index:]
184
217
 
185
218
  is_regex = 'r' in prefix
@@ -191,7 +224,8 @@ class TreeToExpr(Transformer):
191
224
  whole_word='w' in prefix,
192
225
  case_sensitive='c' in prefix,
193
226
  fuzzy='f' in prefix,
194
- fuzzy_level=self.fuzzy_level
227
+ fuzzy_level=self.fuzzy_level,
228
+ full_path='p' in prefix
195
229
  )
196
230
 
197
231
  def and_expr(self, args):
@@ -220,7 +254,8 @@ def parse_query_expression(config) -> ExprNode:
220
254
  config.word,
221
255
  config.case_sensitive,
222
256
  config.fuzzy,
223
- config.fuzzy_level
257
+ config.fuzzy_level,
258
+ config.full_path
224
259
  )
225
260
 
226
261
  # Otherwise, parse using Lark
@@ -232,8 +267,12 @@ def parse_query_expression(config) -> ExprNode:
232
267
  raise click.exceptions.Exit(1)
233
268
 
234
269
 
235
- def find_term_matches(node: TermNode, text: str, num: int) -> list[tuple[int, int]]:
270
+ def find_term_matches(node: TermNode, text: str | Path, num: int) -> list[tuple[int, int]]:
236
271
  """Find matching spans for a single term"""
272
+ if isinstance(text, Path):
273
+ text = text.name if not node.full_path else str(text)
274
+ # Calculate number of chars that come before name of file or dir
275
+ num -= len(text)
237
276
 
238
277
  if node.fuzzy:
239
278
  # Fuzzy partial matching currently has no span extraction
@@ -270,7 +309,7 @@ def find_term_matches(node: TermNode, text: str, num: int) -> list[tuple[int, in
270
309
 
271
310
  def evaluate_with_matches(
272
311
  node: ExprNode,
273
- text: str,
312
+ text: str | Path,
274
313
  num: int,
275
314
  positive: bool = True
276
315
  ) -> tuple[bool, list[tuple[int, int]]]:
@@ -370,12 +409,10 @@ def evaluate_with_matches(
370
409
 
371
410
  return True, matches
372
411
 
373
- raise TypeError(
374
- f'Unsupported expression node: {type(node).__name__}'
375
- )
412
+ raise TypeError(f'Unsupported expression node: {type(node).__name__}')
376
413
 
377
414
 
378
- def find_matches(expr: ExprNode, text: str, num: int = 0) -> list[tuple[int, int]]:
415
+ def find_matches(expr: ExprNode, text: str | Path, num: int = 0) -> list[tuple[int, int]]:
379
416
  """Find spans that contribute to a successful expression"""
380
417
 
381
418
  if expr is None:
@@ -68,15 +68,13 @@ def search_file_and_dir(config, matches: dict, pattern, p: Path,
68
68
  'directory' if config.directory and p.is_dir() else
69
69
  None
70
70
  )
71
- p_name = p.name if not config.full_path else path_str
72
71
 
73
- if match_type and (pattern is None or pattern.evaluate(p_name)):
72
+ if match_type and (pattern is None or pattern.evaluate(p)):
74
73
  # Find matched query in the name
75
74
  name_matches = find_matches(
76
75
  pattern,
77
- p_name,
78
- # Calculate number of chars that come before name of file or dir
79
- len(path_str) - len(p_name)
76
+ p,
77
+ len(path_str)
80
78
  )
81
79
 
82
80
  add_result(
@@ -131,14 +129,12 @@ def search_file_and_dir(config, matches: dict, pattern, p: Path,
131
129
  'directory' if config.directory and is_dir else
132
130
  None
133
131
  )
134
- virtual_name = name.name if not config.full_path else name_str
135
-
136
- if arc_match_type and (pattern is None or pattern.evaluate(virtual_name)):
132
+
133
+ if arc_match_type and (pattern is None or pattern.evaluate(name)):
137
134
  name_matches = find_matches(
138
135
  pattern,
139
- virtual_name,
140
- # Calculate number of chars that come before name of file or dir
141
- len(name_str) - len(virtual_name)
136
+ name,
137
+ len(name_str)
142
138
  )
143
139
 
144
140
  add_result(
@@ -310,41 +306,50 @@ def search_content(config, matches: dict, pattern, binary_pattern,
310
306
  return
311
307
 
312
308
  collector = ContextCollector(config.context)
313
- # Memory-map the file for efficient access
314
- with open(p, 'rb') as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
315
- head = mm[:8192]
316
- if is_binary(head) or (binary_pattern and not content_contains(mm, binary_pattern)):
317
- return
309
+ try:
310
+ # Memory-map the file for efficient access
311
+ with open(p, 'rb') as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
312
+ head = mm[:8192]
313
+ if is_binary(head) or (binary_pattern and not content_contains(mm, binary_pattern)):
314
+ return
318
315
 
319
- mm.seek(0) # Move the cursor to the beginning of the file
316
+ mm.seek(0) # Move the cursor to the beginning of the file
320
317
 
321
- # Iterate over each line in the file
322
- for num, line in enumerate(iter(mm.readline, b''), 1):
323
- try:
324
- line_decoded = line.decode('utf-8').rstrip('\r\n')
325
- except UnicodeDecodeError:
326
- # Skip lines that can't be decoded
327
- continue
318
+ # Iterate over each line in the file
319
+ for num, line in enumerate(iter(mm.readline, b''), 1):
320
+ if binary_pattern and not content_contains(line, binary_pattern):
321
+ continue
328
322
 
329
- matched = pattern is None or pattern.evaluate(line_decoded)
323
+ try:
324
+ line_decoded = line.decode('utf-8').rstrip('\r\n')
325
+ except UnicodeDecodeError:
326
+ # Skip lines that can't be decoded
327
+ continue
330
328
 
331
- # Avoid searching through the entire file content if the paths-only flag is True
332
- if config.paths_only and matched:
333
- add_result(
334
- matches,
335
- result_queue,
336
- 'content',
337
- ContentResult(path=path_str),
338
- result_lock
339
- )
340
- return
329
+ matched = pattern is None or pattern.evaluate(line_decoded)
330
+
331
+ # Avoid searching through the entire file content if the paths-only flag is True
332
+ if config.paths_only and matched:
333
+ add_result(
334
+ matches,
335
+ result_queue,
336
+ 'content',
337
+ ContentResult(path=path_str),
338
+ result_lock
339
+ )
340
+ return
341
+
342
+ if not any(config.context) and not matched:
343
+ continue
341
344
 
342
- line_instance = Line(num, line_decoded)
345
+ line_instance = Line(num, line_decoded)
343
346
 
344
- if matched:
345
- line_instance.matches = find_matches(pattern, line_decoded)
347
+ if matched:
348
+ line_instance.matches = find_matches(pattern, line_decoded)
346
349
 
347
- collector.process(line_instance, matched)
350
+ collector.process(line_instance, matched)
351
+ except OSError:
352
+ return
348
353
 
349
354
  groups = collector.finish()
350
355
  if groups:
@@ -452,7 +457,7 @@ def walk_logic(path: Path, config, depth: int, matcher, ancestors: set):
452
457
  ancestors.remove(dir_key)
453
458
 
454
459
 
455
- # TODO: Make traversal parallelize just like seek func
460
+ # TODO: Make traversal parallel just like seek func
456
461
  def walk(config):
457
462
  """Include paths define traversal roots, avoiding unnecessary traversal
458
463
  of unrelated parts of the tree"""
@@ -24,13 +24,19 @@ def compile_regex(txt, flags=0) -> re.Pattern | None:
24
24
  raise click.exceptions.Exit(1)
25
25
 
26
26
 
27
- def get_path_suffix(path: Path | str) -> str:
27
+ def get_path_suffix(path: Path | str, is_dir: bool | None = None) -> str:
28
28
  """ If multiple file suffixes are valid, return them, otherwise return only the last suffix """
29
29
  if isinstance(path, str):
30
30
  path = Path(path)
31
31
 
32
- if path.is_dir():
33
- return None
32
+ # The paths within archive aren't physical paths,
33
+ # so we need to determine is_dir from their metadata.
34
+ if is_dir is not None:
35
+ if is_dir:
36
+ return None
37
+ else:
38
+ if path.is_dir():
39
+ return None
34
40
 
35
41
  suffixes = ''.join(path.suffixes)[1:].lower()
36
42
 
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "pseek"
7
- version = "3.6.0"
7
+ version = "3.6.2"
8
8
  description = "Pseek is a Python CLI toolkit to search files, folders, and text"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes