pseek 1.0.1__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.
- pseek-1.0.1/LICENSE +21 -0
- pseek-1.0.1/PKG-INFO +102 -0
- pseek-1.0.1/README.md +78 -0
- pseek-1.0.1/pseek/__init__.py +0 -0
- pseek-1.0.1/pseek/cli.py +65 -0
- pseek-1.0.1/pseek/searcher.py +106 -0
- pseek-1.0.1/pseek/utils.py +66 -0
- pseek-1.0.1/pseek.egg-info/PKG-INFO +102 -0
- pseek-1.0.1/pseek.egg-info/SOURCES.txt +13 -0
- pseek-1.0.1/pseek.egg-info/dependency_links.txt +1 -0
- pseek-1.0.1/pseek.egg-info/entry_points.txt +2 -0
- pseek-1.0.1/pseek.egg-info/requires.txt +1 -0
- pseek-1.0.1/pseek.egg-info/top_level.txt +1 -0
- pseek-1.0.1/setup.cfg +4 -0
- pseek-1.0.1/setup.py +24 -0
pseek-1.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Arian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pseek-1.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pseek
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Pseek is a Python library to search files, folders, and text
|
|
5
|
+
Home-page: https://github.com/ArianN8610/pysearch
|
|
6
|
+
Author: Arian
|
|
7
|
+
Author-email: ariannasiri86@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click==8.1.8
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# Pseek
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
A powerful command-line tool for searching files, directories, and content inside files efficiently. The tool supports searching by name, content, extensions, and more with advanced filtering options.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
* **Search in file & folder names**
|
|
34
|
+
* **Search inside file contents**
|
|
35
|
+
* **Highlight matches** in terminal output
|
|
36
|
+
* **Optimized for speed** with ThreadPoolExecutor
|
|
37
|
+
* **Cross-platform** (Linux, macOS, Windows)
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
### **1️⃣ Install via `pip` (Recommended)**
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pip install pseek
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### **2️⃣ Install from source**
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
git clone https://github.com/ArianN8610/pysearch.git
|
|
51
|
+
cd pseek
|
|
52
|
+
pip install click==8.1.8
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
Run the command with a search query:
|
|
58
|
+
```sh
|
|
59
|
+
pseek <query> [options]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Examples
|
|
63
|
+
|
|
64
|
+
### Search for a keyword in file & folder names
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
pseek "my_keyword" --path /path/to/search --file --directory
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Search inside file contents
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
pseek "error" --path /var/logs --content
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Search only in specific file types
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
pseek "TODO" --path ./projects --ext py --ext txt
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Search by regex
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
pseek "error\d+" --regex
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Command Options
|
|
89
|
+
|
|
90
|
+
| Option | Description |
|
|
91
|
+
|----------------------------|--------------------------------------------------------------|
|
|
92
|
+
| `--path` | Base directory to search in (default: current directory `.`) |
|
|
93
|
+
| `--file` | Search only in file names |
|
|
94
|
+
| `--directory` | Search only in directory names |
|
|
95
|
+
| `--content` | Search inside file contents |
|
|
96
|
+
| `--ext` | Filter by file extension (e.g., `.txt`, `.log`) |
|
|
97
|
+
| `--case-sensitive` | Make the search case-sensitive |
|
|
98
|
+
| `--regex` | Use regular expression for searching |
|
|
99
|
+
| `--include`, `--exclude` | Limit search results to specific set of directories or files |
|
|
100
|
+
| `--word` | Match the whole word only |
|
|
101
|
+
| `--max-size`, `--min-size` | Specify maximum and minimum sizes for files and directories |
|
|
102
|
+
| `--full-path` | Display full path of files and directories |
|
pseek-1.0.1/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Pseek
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A powerful command-line tool for searching files, directories, and content inside files efficiently. The tool supports searching by name, content, extensions, and more with advanced filtering options.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
* **Search in file & folder names**
|
|
10
|
+
* **Search inside file contents**
|
|
11
|
+
* **Highlight matches** in terminal output
|
|
12
|
+
* **Optimized for speed** with ThreadPoolExecutor
|
|
13
|
+
* **Cross-platform** (Linux, macOS, Windows)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### **1️⃣ Install via `pip` (Recommended)**
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pip install pseek
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### **2️⃣ Install from source**
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
git clone https://github.com/ArianN8610/pysearch.git
|
|
27
|
+
cd pseek
|
|
28
|
+
pip install click==8.1.8
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Run the command with a search query:
|
|
34
|
+
```sh
|
|
35
|
+
pseek <query> [options]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
### Search for a keyword in file & folder names
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pseek "my_keyword" --path /path/to/search --file --directory
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Search inside file contents
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pseek "error" --path /var/logs --content
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Search only in specific file types
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
pseek "TODO" --path ./projects --ext py --ext txt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Search by regex
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
pseek "error\d+" --regex
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Command Options
|
|
65
|
+
|
|
66
|
+
| Option | Description |
|
|
67
|
+
|----------------------------|--------------------------------------------------------------|
|
|
68
|
+
| `--path` | Base directory to search in (default: current directory `.`) |
|
|
69
|
+
| `--file` | Search only in file names |
|
|
70
|
+
| `--directory` | Search only in directory names |
|
|
71
|
+
| `--content` | Search inside file contents |
|
|
72
|
+
| `--ext` | Filter by file extension (e.g., `.txt`, `.log`) |
|
|
73
|
+
| `--case-sensitive` | Make the search case-sensitive |
|
|
74
|
+
| `--regex` | Use regular expression for searching |
|
|
75
|
+
| `--include`, `--exclude` | Limit search results to specific set of directories or files |
|
|
76
|
+
| `--word` | Match the whole word only |
|
|
77
|
+
| `--max-size`, `--min-size` | Specify maximum and minimum sizes for files and directories |
|
|
78
|
+
| `--full-path` | Display full path of files and directories |
|
|
File without changes
|
pseek-1.0.1/pseek/cli.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import click
|
|
3
|
+
|
|
4
|
+
from .utils import display_results
|
|
5
|
+
from .searcher import search_in_names, search_in_file_contents
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.command()
|
|
9
|
+
@click.argument('query')
|
|
10
|
+
@click.option('-p', '--path', type=click.Path(exists=True, file_okay=False, dir_okay=True), default='.',
|
|
11
|
+
show_default=True, help='Base directory to search in.')
|
|
12
|
+
@click.option('-f', '--file', is_flag=True, help='Search only in file names.')
|
|
13
|
+
@click.option('-d', '--directory', is_flag=True, help='Search only in directory names.')
|
|
14
|
+
@click.option('-c', '--content', is_flag=True, help='Search inside file contents.')
|
|
15
|
+
@click.option('-C', '--case-sensitive', is_flag=True, help='Make the search case-sensitive.')
|
|
16
|
+
@click.option('--ext', multiple=True, type=click.STRING,
|
|
17
|
+
help='Filter results by file extension. Example: --ext py --ext js')
|
|
18
|
+
@click.option('--regex', is_flag=True, help='Use regular expression for searching.')
|
|
19
|
+
@click.option('-i', '--include', type=click.Path(exists=True, file_okay=True, dir_okay=True),
|
|
20
|
+
multiple=True, help='Directories or files that contain search results.')
|
|
21
|
+
@click.option('-e', '--exclude', type=click.Path(exists=True, file_okay=True, dir_okay=True),
|
|
22
|
+
multiple=True, help='Directories or files not included in search results.')
|
|
23
|
+
@click.option('--word', is_flag=True, help='Search for results that match the whole word.')
|
|
24
|
+
@click.option('--max-size', type=click.FLOAT, help='Maximum size directory or file can have (MB)')
|
|
25
|
+
@click.option('--min-size', type=click.FLOAT, help='Minimum size directory or file can have (MB)')
|
|
26
|
+
@click.option('--full-path', is_flag=True, help='Display complete paths of files and directories.')
|
|
27
|
+
def search(query, path, file, directory, content, case_sensitive, ext, regex, include, exclude, word,
|
|
28
|
+
max_size, min_size, full_path):
|
|
29
|
+
"""Search for files, directories, and content based on the query."""
|
|
30
|
+
|
|
31
|
+
if regex:
|
|
32
|
+
try:
|
|
33
|
+
re.compile(query) # Ensure valid regex
|
|
34
|
+
except re.error:
|
|
35
|
+
click.echo(click.style('Invalid regex pattern: ', fg='red') + query)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# Enable all search types if none are explicitly selected
|
|
39
|
+
if not any([file, directory, content]):
|
|
40
|
+
file = directory = content = True
|
|
41
|
+
|
|
42
|
+
results = []
|
|
43
|
+
|
|
44
|
+
if file:
|
|
45
|
+
filename_results = search_in_names(path, query, case_sensitive, regex, include, exclude, word, max_size,
|
|
46
|
+
min_size, full_path, ext)
|
|
47
|
+
display_results(filename_results, 'Files', 'file')
|
|
48
|
+
results.extend(filename_results)
|
|
49
|
+
if directory and not ext:
|
|
50
|
+
dir_results = search_in_names(path, query, case_sensitive, regex, include, exclude, word, max_size, min_size,
|
|
51
|
+
full_path, is_file=False)
|
|
52
|
+
display_results(dir_results, 'Directories', 'directory')
|
|
53
|
+
results.extend(dir_results)
|
|
54
|
+
if content:
|
|
55
|
+
content_results = search_in_file_contents(path, query, case_sensitive, ext, regex, include, exclude, word,
|
|
56
|
+
max_size, min_size, full_path)
|
|
57
|
+
display_results(content_results, 'Contents', 'content')
|
|
58
|
+
results.extend(content_results)
|
|
59
|
+
|
|
60
|
+
message = f'\nTotal results: {len(results)}' if results else 'No results found'
|
|
61
|
+
click.echo(click.style(message, fg='red')) # Display total of results
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
search()
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import click
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
|
|
6
|
+
from .utils import highlight_matches, safe_is_file
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def search_in_names(base_path, query, case_sensitive, regex, include, exclude, whole_word, max_size, min_size,
|
|
10
|
+
full_path, ext=tuple(), is_file=True):
|
|
11
|
+
"""Search for file and folder names"""
|
|
12
|
+
base_path = Path(base_path)
|
|
13
|
+
matches = []
|
|
14
|
+
|
|
15
|
+
if not regex:
|
|
16
|
+
query = re.escape(query) # If regex is disabled, convert query to plain text
|
|
17
|
+
|
|
18
|
+
if whole_word:
|
|
19
|
+
query = rf'\b{query}\b' # Ensure search for whole words
|
|
20
|
+
|
|
21
|
+
flags = 0 if case_sensitive else re.IGNORECASE # Adjust case sensitivity
|
|
22
|
+
|
|
23
|
+
# Convert include and exclude paths to `Path`
|
|
24
|
+
include_paths = {Path(p).resolve() for p in include}
|
|
25
|
+
exclude_paths = {Path(p).resolve() for p in exclude}
|
|
26
|
+
|
|
27
|
+
for p in base_path.rglob('*'):
|
|
28
|
+
p_resolved = p.resolve() # Actual file or folder path
|
|
29
|
+
p_size_mb = p_resolved.stat().st_size / 1_048_576 # Convert to MB
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
# If include is given, at least one of them must be present in the name
|
|
33
|
+
(include and not any(p_resolved.is_relative_to(inc) for inc in include_paths))
|
|
34
|
+
# If exclude is given, none should be in the name
|
|
35
|
+
or (exclude and any(p_resolved.is_relative_to(exc) for exc in exclude_paths))
|
|
36
|
+
# Prevent unnecessary continuation in case of type mismatch
|
|
37
|
+
or (is_file and ext and p.suffix[1:] not in ext)
|
|
38
|
+
# Check file or directory size
|
|
39
|
+
or (max_size and p_size_mb > max_size)
|
|
40
|
+
or (min_size and p_size_mb < min_size)
|
|
41
|
+
):
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
if re.search(query, p.name, flags) and ((is_file and p.is_file()) or (not is_file and p.is_dir())):
|
|
45
|
+
# Specify the found part
|
|
46
|
+
highlighted_name = re.sub(query, lambda m: click.style(m.group(), fg='green'), p.name, flags=flags)
|
|
47
|
+
p_parent = p_resolved.parent if full_path else p.parent # Get full path if full_path is True
|
|
48
|
+
matches.append(f'{p_parent}\\{highlighted_name}')
|
|
49
|
+
|
|
50
|
+
return matches
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def search_in_file_contents(base_path, query, case_sensitive, ext, regex, include, exclude, whole_word,
|
|
54
|
+
max_size, min_size, full_path):
|
|
55
|
+
"""Search inside file contents"""
|
|
56
|
+
base_path = Path(base_path)
|
|
57
|
+
matches = []
|
|
58
|
+
|
|
59
|
+
if not regex:
|
|
60
|
+
query = re.escape(query)
|
|
61
|
+
|
|
62
|
+
if whole_word:
|
|
63
|
+
query = rf'\b{query}\b'
|
|
64
|
+
|
|
65
|
+
flags = 0 if case_sensitive else re.IGNORECASE
|
|
66
|
+
|
|
67
|
+
include_paths = {Path(p).resolve() for p in include}
|
|
68
|
+
exclude_paths = {Path(p).resolve() for p in exclude}
|
|
69
|
+
|
|
70
|
+
def process_file(file_path):
|
|
71
|
+
"""Processes a single file and searches for the query inside its content."""
|
|
72
|
+
p_resolved = file_path.resolve()
|
|
73
|
+
p_size_mb = p_resolved.stat().st_size / 1_048_576
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
# Filter by include/exclude directories
|
|
77
|
+
(include and not any(p_resolved.is_relative_to(inc) for inc in include_paths))
|
|
78
|
+
or (exclude and any(p_resolved.is_relative_to(exc) for exc in exclude_paths))
|
|
79
|
+
# Filter by extension
|
|
80
|
+
or (ext and p_resolved.suffix[1:] not in ext)
|
|
81
|
+
# Filter by file size
|
|
82
|
+
or (max_size and p_size_mb > max_size)
|
|
83
|
+
or (min_size and p_size_mb < min_size)
|
|
84
|
+
):
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
for num, line in enumerate(p_resolved.read_text(encoding='utf-8', errors='ignore').splitlines(), 1):
|
|
89
|
+
line = line.strip()
|
|
90
|
+
|
|
91
|
+
if re.search(query, line, flags):
|
|
92
|
+
highlighted_snippet, count_query = highlight_matches(line, query, case_sensitive, regex, whole_word)
|
|
93
|
+
file_path = p_resolved if full_path else file_path
|
|
94
|
+
matches.append(
|
|
95
|
+
click.style(file_path, fg='cyan')
|
|
96
|
+
+ click.style(f' (Line {num}) (Repeated {count_query} time(s)): ', fg='magenta')
|
|
97
|
+
+ highlighted_snippet
|
|
98
|
+
)
|
|
99
|
+
except Exception:
|
|
100
|
+
return # Ignore unreadable files
|
|
101
|
+
|
|
102
|
+
# Use multi-threading for faster processing
|
|
103
|
+
with ThreadPoolExecutor() as executor:
|
|
104
|
+
executor.map(process_file, (file for file in base_path.rglob('*') if safe_is_file(file)))
|
|
105
|
+
|
|
106
|
+
return matches
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import click
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def highlight_matches(line, query, case_sensitive, regex, whole_word, context=20):
|
|
6
|
+
"""Highlight matches and truncate long lines with proper handling"""
|
|
7
|
+
|
|
8
|
+
flags = 0 if case_sensitive else re.IGNORECASE
|
|
9
|
+
|
|
10
|
+
if not regex and not whole_word:
|
|
11
|
+
query = re.escape(query) # If regex is disabled, use escape to search for regular text
|
|
12
|
+
|
|
13
|
+
# Find all matches
|
|
14
|
+
matches = list(re.finditer(query, line, flags))
|
|
15
|
+
|
|
16
|
+
if not matches:
|
|
17
|
+
return None # If there is no match, return None
|
|
18
|
+
|
|
19
|
+
start_positions = [max(0, m.start() - context) for m in matches] # 20 characters before
|
|
20
|
+
end_positions = [min(len(line), m.end() + context) for m in matches] # 20 characters after
|
|
21
|
+
|
|
22
|
+
# Combine sections close together to avoid repetition
|
|
23
|
+
merged_snippets = []
|
|
24
|
+
current_start, current_end = start_positions[0], end_positions[0]
|
|
25
|
+
|
|
26
|
+
for i in range(1, len(matches)):
|
|
27
|
+
if start_positions[i] <= current_end: # If the next section is close, combine them
|
|
28
|
+
current_end = max(current_end, end_positions[i])
|
|
29
|
+
else:
|
|
30
|
+
merged_snippets.append((current_start, current_end))
|
|
31
|
+
current_start, current_end = start_positions[i], end_positions[i]
|
|
32
|
+
|
|
33
|
+
merged_snippets.append((current_start, current_end)) # Add the last section
|
|
34
|
+
|
|
35
|
+
result = []
|
|
36
|
+
for start, end in merged_snippets:
|
|
37
|
+
snippet = line[start:end]
|
|
38
|
+
snippet = re.sub(query, lambda m: click.style(m.group(), fg='green'), snippet, flags=flags)
|
|
39
|
+
result.append(snippet)
|
|
40
|
+
|
|
41
|
+
final_output = ' ... '.join(result) # If there are multiple results, put `...` between them
|
|
42
|
+
|
|
43
|
+
# Add `...` at the beginning and end if needed
|
|
44
|
+
if merged_snippets[0][0] > 0:
|
|
45
|
+
final_output = '...' + final_output
|
|
46
|
+
if merged_snippets[-1][1] < len(line):
|
|
47
|
+
final_output += '...'
|
|
48
|
+
|
|
49
|
+
return final_output, len(matches) # Count the number of repetitions
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def safe_is_file(file):
|
|
53
|
+
"""Check if a file is accessible and return True/False."""
|
|
54
|
+
try:
|
|
55
|
+
return file.is_file()
|
|
56
|
+
except OSError:
|
|
57
|
+
return False # Ignore files that cannot be accessed
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def display_results(results, title, result_name):
|
|
61
|
+
"""Display search results"""
|
|
62
|
+
if results:
|
|
63
|
+
click.echo(click.style(f'\n{title}:\n', fg='yellow'))
|
|
64
|
+
for result in results:
|
|
65
|
+
click.echo(result)
|
|
66
|
+
click.echo(click.style(f'\n{len(results)} result(s) found for {result_name}', fg='blue'))
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pseek
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Pseek is a Python library to search files, folders, and text
|
|
5
|
+
Home-page: https://github.com/ArianN8610/pysearch
|
|
6
|
+
Author: Arian
|
|
7
|
+
Author-email: ariannasiri86@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click==8.1.8
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# Pseek
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
A powerful command-line tool for searching files, directories, and content inside files efficiently. The tool supports searching by name, content, extensions, and more with advanced filtering options.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
* **Search in file & folder names**
|
|
34
|
+
* **Search inside file contents**
|
|
35
|
+
* **Highlight matches** in terminal output
|
|
36
|
+
* **Optimized for speed** with ThreadPoolExecutor
|
|
37
|
+
* **Cross-platform** (Linux, macOS, Windows)
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
### **1️⃣ Install via `pip` (Recommended)**
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pip install pseek
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### **2️⃣ Install from source**
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
git clone https://github.com/ArianN8610/pysearch.git
|
|
51
|
+
cd pseek
|
|
52
|
+
pip install click==8.1.8
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
Run the command with a search query:
|
|
58
|
+
```sh
|
|
59
|
+
pseek <query> [options]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Examples
|
|
63
|
+
|
|
64
|
+
### Search for a keyword in file & folder names
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
pseek "my_keyword" --path /path/to/search --file --directory
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Search inside file contents
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
pseek "error" --path /var/logs --content
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Search only in specific file types
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
pseek "TODO" --path ./projects --ext py --ext txt
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Search by regex
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
pseek "error\d+" --regex
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Command Options
|
|
89
|
+
|
|
90
|
+
| Option | Description |
|
|
91
|
+
|----------------------------|--------------------------------------------------------------|
|
|
92
|
+
| `--path` | Base directory to search in (default: current directory `.`) |
|
|
93
|
+
| `--file` | Search only in file names |
|
|
94
|
+
| `--directory` | Search only in directory names |
|
|
95
|
+
| `--content` | Search inside file contents |
|
|
96
|
+
| `--ext` | Filter by file extension (e.g., `.txt`, `.log`) |
|
|
97
|
+
| `--case-sensitive` | Make the search case-sensitive |
|
|
98
|
+
| `--regex` | Use regular expression for searching |
|
|
99
|
+
| `--include`, `--exclude` | Limit search results to specific set of directories or files |
|
|
100
|
+
| `--word` | Match the whole word only |
|
|
101
|
+
| `--max-size`, `--min-size` | Specify maximum and minimum sizes for files and directories |
|
|
102
|
+
| `--full-path` | Display full path of files and directories |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
pseek/__init__.py
|
|
5
|
+
pseek/cli.py
|
|
6
|
+
pseek/searcher.py
|
|
7
|
+
pseek/utils.py
|
|
8
|
+
pseek.egg-info/PKG-INFO
|
|
9
|
+
pseek.egg-info/SOURCES.txt
|
|
10
|
+
pseek.egg-info/dependency_links.txt
|
|
11
|
+
pseek.egg-info/entry_points.txt
|
|
12
|
+
pseek.egg-info/requires.txt
|
|
13
|
+
pseek.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
click==8.1.8
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pseek
|
pseek-1.0.1/setup.cfg
ADDED
pseek-1.0.1/setup.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", encoding="utf-8") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="pseek",
|
|
8
|
+
version="1.0.1",
|
|
9
|
+
author="Arian",
|
|
10
|
+
author_email="ariannasiri86@gmail.com",
|
|
11
|
+
description="Pseek is a Python library to search files, folders, and text",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/ArianN8610/pysearch",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
],
|
|
21
|
+
python_requires=">=3.6",
|
|
22
|
+
install_requires=["click==8.1.8"],
|
|
23
|
+
entry_points={"console_scripts": ["pseek=pseek.cli:search"]}
|
|
24
|
+
)
|