A powerful and intuitive file selection browser for CLI applications using the Textual TUI framework
β οΈ EARLY ALPHA WARNING: This project is in early alpha stage and is NOT ready for production use. APIs may change, and stability is not guaranteed. Use at your own risk!
- Features
- Requirements
- Installation
- Quick Start
- Usage Examples
- Keyboard Controls
- Development
- Workflows
- Contributing
- License
- Support
- Acknowledgments
- π¨ Modern TUI - Built with the powerful Textual framework for beautiful terminal interfaces
- π Intuitive Navigation - Easy file and directory browsing with keyboard controls
- π Advanced Sorting - Multiple sort modes: Name, Date, Size, Extension with memory
- β¨οΈ Keyboard-Driven - Fully accessible via keyboard with vim-style shortcuts
- π― Simple API - Just one function call:
select_file()with backward compatibility - π₯οΈ Cross-Platform - Works on Linux, macOS, and Windows (experimental)
- π§ͺ Well-Tested - 93.92% test coverage with snapshot testing
- π¦ Zero Config - Works out of the box, no configuration needed
- π Enhanced DateTime Display - Fixed 24h format with emojis:
πYYYY-MM-DD πHH:MM:SS - π File Size Formatting - Localized number formatting with proper units (KB, MB, GB)
- π― Visual Navigation - Emoji buttons with underlined shortcuts: πΌParent(u) π Home(h) β«Root(r)
- π¨ ls-style Visual Cues - File type indicators:
/dirs,*executable,@symlinks - β¨ Virtual Environment Detection - Folders containing Python venvs marked with β¨
- π Folder Selection - Select directories with configurable options
- π Comprehensive FileInfo - Returns detailed file/folder information
- π Performance - Async loading with visual feedback, column-aligned entries
- β Error Handling - Graceful error messages in FileInfo.error_message
- π Responsive UI - Real-time terminal resizing support
- Python: 3.10 or higher
- Terminal: Unicode support required
- OS: Linux, macOS, or Windows (experimental)
pip install selectfilecliuv pip install selectfilecligit clone https://github.com/Emasoft/SelectFileCLI.git
cd SelectFileCLI
pip install -e .git clone https://github.com/Emasoft/SelectFileCLI.git
cd SelectFileCLI
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"from selectfilecli import select_file
# Open file browser in current directory
selected_file = select_file()
if selected_file:
print(f"You selected: {selected_file}")
else:
print("No file selected")from selectfilecli import select_file
# Returns string path for backward compatibility
selected_file = select_file()
if selected_file:
print(f"You selected: {selected_file}")
else:
print("No file selected")from selectfilecli import select_file
# Get comprehensive file information
result = select_file(return_info=True)
if result and result.error_message:
print(f"Error: {result.error_message}")
elif result and result.file_path:
print(f"π File: {result.file_path}")
print(f" Size: {result.size_in_bytes:,} bytes")
print(f" Modified: π{result.last_modified_datetime:%Y-%m-%d} π{result.last_modified_datetime:%H:%M:%S}")
print(f" Read-only: {'Yes β' if result.readonly else 'No β
'}")
if result.is_symlink:
print(f" Symlink: {'Broken ππ' if result.symlink_broken else 'Yes π'}")from selectfilecli import select_file
# Select folders only
result = select_file(
select_files=False,
select_dirs=True,
return_info=True
)
if result and result.folder_path:
print(f"π Folder: {result.folder_path}")
print(f" Has venv: {'Yes β¨' if result.folder_has_venv else 'No'}")
if result.size_in_bytes:
print(f" Size: {result.size_in_bytes:,} bytes (recursive)")from selectfilecli import select_file
# Allow selection of both files and folders
# Press 'd' to select current directory, Enter for files
result = select_file(
select_files=True,
select_dirs=True,
return_info=True
)
if result:
if result.file_path:
print(f"Selected file: {result.file_path}")
elif result.folder_path:
print(f"Selected folder: {result.folder_path}")import click
from selectfilecli import select_file
@click.command()
@click.option('--input-file', help='Input file path')
def process_file(input_file):
if not input_file:
# Let user select file interactively with detailed info
result = select_file(return_info=True)
if not result or not result.file_path:
click.echo("No file selected.")
return
input_file = result.file_path
click.echo(f"Processing: {input_file}")
click.echo(f"File size: {result.size_in_bytes:,} bytes")
# Your processing logic here
if __name__ == '__main__':
process_file()from pathlib import Path
from selectfilecli import select_file
def load_config():
config_dir = Path.home() / '.config' / 'myapp'
# Use backward compatible mode for simple path return
config_file = select_file(str(config_dir))
if config_file and config_file.endswith('.json'):
import json
with open(config_file) as f:
return json.load(f)
else:
print("Please select a valid JSON config file")
return None| Key | Action | Description |
|---|---|---|
β / k |
Move up | Navigate to previous item |
β / j |
Move down | Navigate to next item |
Enter |
Select / Open | Select file or enter directory |
u / Backspace |
Parent Directory πΌ | Navigate to parent directory |
h |
Home Directory π | Go to user's home directory |
r |
Root Directory β« | Go to system root (/) |
d |
Select Directory | Select current directory (when dirs enabled) |
s |
Sort Menu π | Open sort options dialog |
q / Escape |
Cancel β | Exit without selecting |
Ctrl+C |
Force Quit | Immediate exit |
| Key | Action | Description |
|---|---|---|
β / β |
Navigate options | Move between sort modes |
Space |
Toggle order | Switch between ascending/descending |
Enter |
Apply sort | Apply selected sort mode |
Escape |
Cancel | Close dialog without changes |
- Name - Alphabetical order
- Creation Date - When file was created
- Last Accessed - Most recently accessed files
- Last Modified - Most recently modified files
- Size - File size (largest/smallest first)
- Extension - Group by file extension
# Install uv (recommended)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone repository
git clone https://github.com/Emasoft/SelectFileCLI.git
cd SelectFileCLI
# Create virtual environment
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install with dev dependencies
uv pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install# Run all tests
uv run pytest
# Run with coverage report
uv run pytest --cov=src/selectfilecli --cov-report=html
# Run specific test file
uv run pytest tests/test_file_browser_app.py
# Update UI snapshots after changes
uv run pytest --snapshot-update# Format code
uv run ruff format --line-length=320
# Lint code
uv run ruff check --fix
# Type checking
uv run mypy src
# Run all pre-commit hooks
pre-commit run --all-files# Build package
uv build
# Test locally
pip install dist/*.whl
# Publish to PyPI (requires credentials)
uv publishThis project uses GitHub Actions workflows that can be run both locally (via act) and remotely (via GitHub CLI).
Below is a table showing how to trigger each workflow:
| Action (what it does) | Local act <event> |
Remote (gh workflow run) |
Notes |
|---|---|---|---|
| Install dependencies | act install_deps |
gh workflow run install_deps |
Installs project dependencies |
| Lint source files | act lint |
gh workflow run lint |
Runs code quality checks |
| Format code | act format |
gh workflow run format |
Auto-formats code files |
| Run security scanners | act security |
gh workflow run security |
Security vulnerability scan |
| Static / dynamic analysis | act scan |
gh workflow run scan |
Code analysis |
| Run tests | act test |
gh workflow run test |
Execute test suite |
| Run checks & commit | act commit -e '{"inputs":{"message":"msg"}}' |
gh workflow run commit -f message="msg" |
Checks then commits |
| Run tests & push | act push |
gh workflow run push |
Tests then pushes |
| Build & check docs | act docs |
gh workflow run docs |
Documentation build |
| Collect / report metrics | act metrics |
gh workflow run metrics |
Code metrics collection |
| Compile / package project | act build |
gh workflow run build |
Build packages |
| Deploy with Docker | act deploy_on_docker |
gh workflow run deploy_on_docker |
Docker deployment |
| Create versioned release | act release |
gh workflow run release -F version=1.2.3 |
Create and tag release |
| Push code to GitHub | act push_to_github |
gh workflow run push_to_github |
Push changes to remote |
| Create feature branch | act create_feature_branch |
gh workflow run create_feature_branch |
Create new feature branch |
| Create pull request | act create_pull_req |
gh workflow run create_pull_req |
Open new pull request |
| Squash commits | act squash_push |
gh workflow run squash_push |
Squash and push commits |
| View workflow logs | act view_logs |
gh workflow run view_logs |
View CI/CD logs |
| Delete pull request | act delete_pull_req |
gh workflow run delete_pull_req |
Close/delete PR |
| Auto-fix PR issues | act auto_fix_pr |
gh workflow run auto_fix_pr |
Fix PR formatting/linting |
| Bump version | act bump_version |
gh workflow run bump_version |
Update project version |
| Stash untracked files | act stash_untracked |
gh workflow run stash_untracked |
Save untracked changes |
| Restore stashed files | act unstash_untracked |
gh workflow run unstash_untracked |
Restore saved changes |
| Undo last commit | act undo |
gh workflow run undo |
Revert last commit |
| Auto-merge changes | act auto-merge |
gh workflow run auto-merge |
Merge workflow changes |
| Upload to PyPI | act publish_on_pypi |
gh workflow run publish_on_pypi |
Publish to PyPI |
- Docker Required: All workflows require Docker to be running locally
- Act Integration: Act mounts the entire project folder into Docker containers, providing full git access
- Unified Workflows: The same workflows work both locally (via act) and remotely (on GitHub Actions)
- Use Workflows (
act): For all operations including git operations (commits, branches, PRs, releases) - SEP Integration: All workflows use SEP (Sequential Execution Pipeline) internally for command sequencing
- Git Hooks: Pre-commit and pre-push hooks use act to run validation workflows
- Auto-merge: New workflow automatically merges changes from all other workflows
For detailed documentation:
- DOCS_DEV/WORKFLOW_COMMANDS.md - Full workflow reference
- DOCS_DEV/WORKFLOWS_VS_SCRIPTS_GUIDE.md - When to use workflows vs scripts
Contributions are welcome! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
act create_feature_branch -e '{"inputs":{"branch_name":"amazing-feature"}}') - Commit your changes (
act commit -e '{"inputs":{"message":"Add amazing feature"}}') - Push to the branch (
act push -e '{"inputs":{"branch":"feature/amazing-feature"}}') - Open a Pull Request (
act create_pull_req)
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2024 Emasoft
- π Report Bugs: GitHub Issues
- π‘ Request Features: Feature Requests
- π¬ Discussions: GitHub Discussions
- π§ Contact: 713559+Emasoft@users.noreply.github.com
Special thanks to these amazing projects:
- Textual - The incredible TUI framework that powers this project
- pytest-textual-snapshot - Snapshot testing for Textual apps
- Ruff - Lightning-fast Python linter
- uv - Blazingly fast Python package manager
Made with β€οΈ by Emasoft
β Star this repository if you find it useful!
