Skip to content

Commit c7dc615

Browse files
committed
v0.1.1 release
1 parent dad6978 commit c7dc615

12 files changed

Lines changed: 485 additions & 212 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
uses: softprops/action-gh-release@v2
3333
with:
3434
name: Release ${{ steps.get_version.outputs.VERSION }}
35-
files: target/release/aperture.exe
35+
files: target/release/Aperture.exe
3636
generate_release_notes: true
3737
env:
3838
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
2-
name = "aperture"
3-
version = "0.1.0"
4-
edition = "2021"
5-
description = "Windows-native diagnostic TUI for power users"
6-
authors = ["Winsight"]
2+
name = "Aperture"
3+
version = "0.1.1"
4+
edition = "2024"
5+
description = "Diagnostic tui for Windows power users"
6+
authors = ["stylebending"]
77
license = "MIT"
88

99
[dependencies]
@@ -21,6 +21,7 @@ windows = { version = "0.58", features = [
2121
"Win32_Security",
2222
"Win32_Storage_FileSystem",
2323
"Win32_System_Diagnostics_Debug",
24+
"Win32_System_SystemInformation",
2425
] }
2526

2627
[profile.release]

README.md

Lines changed: 66 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,25 @@
11
# Aperture
22

3-
A high-performance Windows-native diagnostic TUI for power users and developers.
3+
Diagnostic tui for Windows power users
44

5-
Aperture bridges the gap between the Linux `btop`/`lsof` experience and Windows' deep diagnostic capabilities (Processes, Services, and Network). Unlike cross-platform tools, Aperture focuses on Windows-specific pain points: file locks, service management, and process-to-socket mapping.
6-
7-
## Features
8-
9-
### The Locker (Process Management)
10-
- View all running processes with PID, name, path, CPU%, and memory usage
11-
- Real-time CPU and memory metrics with intelligent caching
12-
- **Sort by**: Name, PID, CPU usage, Memory usage
13-
- **Filter** processes by name, path, or PID
14-
- **Kill processes** (requires admin - press `K`)
15-
- **Find file locks** - Identify which processes are locking specific files (press `f`)
16-
17-
### The Controller (Service Management)
18-
- List all Windows services with status, start type, and process ID
19-
- **Start/Stop services** (requires admin - press `Enter`)
20-
- **Sort by**: Name, Status, Service Type
21-
- **Filter** services by name or display name
22-
23-
### The Nexus (Network Monitor)
24-
- Real-time TCP/UDP connection listing
25-
- Map connections to process PIDs and names
26-
- View connection states (ESTABLISHED, LISTENING, etc.)
27-
- **Sort by**: Connection State, PID, Protocol
28-
- **Filter** connections by address, port, or PID
5+
## Installation
296

30-
### UI Features
31-
- **Permanent sidebar** with context-aware keybindings
32-
- **Smart data caching** - All tabs preload for instant switching
33-
- **50ms navigation debounce** - Smooth cursor movement without jitter
34-
- **Change detection** - Only updates when data actually changes
35-
- **Cached metrics** - CPU/memory values persist during temporary data unavailability
7+
### Requirements
368

37-
## Installation
9+
- Windows 10/11
3810

39-
### From Source
40-
```bash
41-
cd aperture
42-
cargo build --release
43-
```
11+
### Download and rune the latest release
4412

45-
The binary will be at `target/release/aperture.exe`.
13+
Download and run the [latest release .exe](https://github.com/stylebending/Aperture/releases/latest)
14+
You're all set! Run as admin to access all features.
4615

4716
### Run from Any Terminal (Add to PATH)
4817

49-
After building, add aperture to your PATH to run it from any terminal:
18+
If you want to run `aperture` from any terminal just add Aperture to your PATH:
5019

51-
**Option 1: Copy to existing PATH directory**
52-
```powershell
53-
# Copy to a directory already in PATH
54-
copy target\release\aperture.exe C:\Windows\System32\
55-
```
20+
**Option 1: Add to user PATH environment variable**
5621

57-
**Option 2: Add to user PATH environment variable**
58-
```powershell
59-
# Add aperture's directory to your user PATH environment variable
60-
```
22+
**Option 2: Copy the Aperture.exe to existing PATH directory**
6123

6224
Then restart your terminal and run `aperture` from anywhere!
6325

@@ -116,30 +78,35 @@ aperture
11678
┌────────────────────────────────────────┐
11779
│ Find Locking Processes │
11880
├────────────────────────────────────────┤
119-
Paths: C:\Users\Me\Documents\file.txt │
81+
Path: C:\Users\Me\Documents\file.txt
12082
│ │
12183
│ Locking processes: │
12284
│ │
12385
│ PID: 5678 notepad.exe │
12486
│ ▶ PID: 9012 chrome.exe │
12587
│ PID: 12345 excel.exe │
12688
│ │
127-
│ [Enter] Search [j/k] Navigate
128-
│ [K] Kill (admin) [Esc] Close
89+
│ [/] Edit Path [Enter] Search
90+
│ [j/k] Navigate [K] Kill [Esc] Close │
12991
└────────────────────────────────────────┘
13092
```
13193

94+
**Note:** Press `/` to enter input mode and type a file path. Enter a folder path to scan all files in that directory.
95+
13296
## Quick Start Guide
13397

13498
### Find What's Locking a File
13599

136100
Can't delete a file because it's "in use"? Aperture can find the culprit:
137101

138102
1. Press `f` to open the **File Lock Search** modal
139-
2. Type the full path to the file (e.g., `C:\Users\You\file.txt`)
140-
3. Press `Enter` to search
141-
4. See which processes have the file locked
142-
5. Navigate with `j`/`k` and press `K` to kill the process (requires admin)
103+
2. Press `/` to enter input mode
104+
3. Type the full path to the file (e.g., `C:\Users\You\file.txt`)
105+
4. Press `Enter` to search
106+
5. See which processes have the file locked
107+
6. Navigate with `j`/`k` and press `K` to kill the process (requires admin)
108+
109+
**Tip:** Enter a folder path to scan all files in that directory and find all locks.
143110

144111
### Kill a Runaway Process
145112

@@ -211,6 +178,10 @@ Each tab supports different sorting:
211178
| | `f` | Find locks | Global | Open file lock search modal |
212179
| **Locker** | `K` | Kill process | Locker only | Kill selected process (admin) |
213180
| **Controller** | `Enter` | Toggle service | Controller only | Start/stop selected service (admin) |
181+
| **File Lock Modal** | `/` | Edit path | Modal | Enter input mode to type path |
182+
| | `Enter` | Search | Modal | Execute search |
183+
| | `j`/`k` | Navigate | Modal | Move up/down results |
184+
| | `K` | Kill | Modal | Kill selected locking process |
214185
| **System** | `q` | Quit | Global | Exit application |
215186

216187
### Search Mode Keybindings
@@ -225,10 +196,15 @@ When in search mode (`/`):
225196

226197
When file lock modal is open (`f`):
227198
- Type file paths (one per line)
199+
- `/` - Enter input mode to edit path (any key including j/k can now be typed)
228200
- `Enter` - Search for locking processes
229-
- `j`/`k` - Navigate results
201+
- `j`/`k` or ``/`` - Navigate results (normal mode only)
230202
- `K` - Kill selected process (admin)
231-
- `Esc` - Close modal
203+
- `Esc` - Close modal (or cancel input mode)
204+
205+
**Directory Scanning:**
206+
- Enter a folder path to scan all files in that directory
207+
- Shows "Scanned X files - Found Y locks" with the count of files checked
232208

233209
## Configuration
234210

@@ -263,11 +239,6 @@ Aperture uses direct Win32 APIs instead of WMI for maximum performance:
263239
- Win32 APIs respond in <50ms
264240
- Essential for smooth TUI experience with 2-second refresh rates
265241

266-
## Requirements
267-
268-
- Windows 10/11
269-
- For full functionality (killing processes, managing services), run as Administrator
270-
271242
## Architecture
272243

273244
```
@@ -333,6 +304,39 @@ aperture/
333304
- [ ] Dark/light theme support
334305
- Currently uses terminal default colors
335306

307+
Aperture bridges the gap between the Linux `btop`/`lsof` experience and Windows' deep diagnostic capabilities (Processes, Services, and Network). Unlike cross-platform tools, Aperture focuses on Windows-specific pain points: file locks, service management, and process-to-socket mapping.
308+
309+
## Features
310+
311+
### The Locker (Process Management)
312+
- View all running processes with PID, name, path, CPU%, and memory usage
313+
- Real-time CPU and memory metrics with intelligent caching
314+
- **Sort by**: Name, PID, CPU usage, Memory usage
315+
- **Filter** processes by name, path, or PID
316+
- **Kill processes** (requires admin - press `K`)
317+
- **Find file locks** - Identify which processes are locking specific files (press `f`)
318+
319+
### The Controller (Service Management)
320+
- List all Windows services with status, start type, and process ID
321+
- **Start/Stop services** (requires admin - press `Enter`)
322+
- **Sort by**: Name, Status, Service Type
323+
- **Filter** services by name or display name
324+
325+
### The Nexus (Network Monitor)
326+
- Real-time TCP/UDP connection listing
327+
- Map connections to process PIDs and names
328+
- View connection states (ESTABLISHED, LISTENING, etc.)
329+
- **Sort by**: Connection State, PID, Protocol
330+
- **Filter** connections by address, port, or PID
331+
332+
### UI Features
333+
- **Vim Motions** keybindings for easy navigation
334+
- **Permanent sidebar** with context-aware keybindings
335+
- **Smart data caching** - All tabs preload for instant switching
336+
- **50ms navigation debounce** - Smooth cursor movement without jitter
337+
- **Change detection** - Only updates when data actually changes
338+
- **Cached metrics** - CPU/memory values persist during temporary data unavailability
339+
336340
## License
337341

338342
MIT

src/app.rs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub enum Modal {
5353
selected: usize,
5454
loading: bool,
5555
error: Option<String>,
56+
is_directory: bool,
57+
files_scanned: Option<usize>,
5658
},
5759
}
5860

@@ -80,6 +82,7 @@ pub struct App {
8082
pub search_query: String,
8183
pub status_message: Option<String>,
8284
pub modal: Option<Modal>,
85+
pub handle_search_input_mode: bool,
8386
}
8487

8588
impl App {
@@ -92,6 +95,7 @@ impl App {
9295
search_query: String::new(),
9396
status_message: None,
9497
modal: None,
98+
handle_search_input_mode: false,
9599
}
96100
}
97101

@@ -236,7 +240,18 @@ impl App {
236240
selected: 0,
237241
loading: false,
238242
error: None,
243+
is_directory: false,
244+
files_scanned: None,
239245
});
246+
self.handle_search_input_mode = false;
247+
}
248+
249+
pub fn enter_handle_search_input_mode(&mut self) {
250+
self.handle_search_input_mode = true;
251+
}
252+
253+
pub fn exit_handle_search_input_mode(&mut self) {
254+
self.handle_search_input_mode = false;
240255
}
241256

242257
pub fn handle_search_modal_char(&mut self, c: char) {
@@ -269,34 +284,67 @@ impl App {
269284
}
270285

271286
let input_str = file_paths.join("\n");
272-
let file_refs: Vec<&str> = file_paths.iter().map(|s| s.as_str()).collect();
287+
let first_path = file_paths.first().map(|p| p.as_str()).unwrap_or("");
288+
let path = std::path::Path::new(first_path);
289+
290+
let is_directory = path.is_dir();
273291

274292
self.modal = Some(Modal::HandleSearch {
275293
input: input_str.clone(),
276294
results: Vec::new(),
277295
selected: 0,
278296
loading: true,
279297
error: None,
298+
is_directory,
299+
files_scanned: None,
280300
});
281301

282-
let result = sys::handle::find_locking_processes(&file_refs);
283-
284-
self.modal = Some(match result {
285-
Ok(locking_procs) => Modal::HandleSearch {
286-
input: input_str,
287-
results: locking_procs,
288-
selected: 0,
289-
loading: false,
290-
error: None,
291-
},
292-
Err(e) => Modal::HandleSearch {
293-
input: input_str,
294-
results: Vec::new(),
295-
selected: 0,
296-
loading: false,
297-
error: Some(e.to_string()),
298-
},
299-
});
302+
if is_directory {
303+
let result = sys::handle::find_locking_processes_in_directory(first_path);
304+
self.modal = Some(match result {
305+
Ok((locking_procs, scanned_count)) => Modal::HandleSearch {
306+
input: input_str,
307+
results: locking_procs,
308+
selected: 0,
309+
loading: false,
310+
error: None,
311+
is_directory,
312+
files_scanned: Some(scanned_count),
313+
},
314+
Err(e) => Modal::HandleSearch {
315+
input: input_str,
316+
results: Vec::new(),
317+
selected: 0,
318+
loading: false,
319+
error: Some(e.to_string()),
320+
is_directory: false,
321+
files_scanned: None,
322+
},
323+
});
324+
} else {
325+
let file_refs: Vec<&str> = file_paths.iter().map(|s| s.as_str()).collect();
326+
let result = sys::handle::find_locking_processes(&file_refs);
327+
self.modal = Some(match result {
328+
Ok(locking_procs) => Modal::HandleSearch {
329+
input: input_str,
330+
results: locking_procs,
331+
selected: 0,
332+
loading: false,
333+
error: None,
334+
is_directory,
335+
files_scanned: None,
336+
},
337+
Err(e) => Modal::HandleSearch {
338+
input: input_str,
339+
results: Vec::new(),
340+
selected: 0,
341+
loading: false,
342+
error: Some(e.to_string()),
343+
is_directory: false,
344+
files_scanned: None,
345+
},
346+
});
347+
}
300348
}
301349

302350
pub fn handle_search_modal_select_next(&mut self) {

0 commit comments

Comments
 (0)