/SelectFileCLI

A handy file selection browser for CLI applications using Textual TUI

Primary LanguageShellMIT LicenseMIT

selectFileCLI

GitHub CI Tests Lint Build codecov

Python Version PyPI Version License: MIT Downloads Code style: ruff

A powerful and intuitive file selection browser for CLI applications using the Textual TUI framework

Demo


⚠️ 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!


πŸ“‹ Table of Contents

✨ Features

  • 🎨 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

New in v0.4.5

  • πŸ“† 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

πŸ“‹ Requirements

  • Python: 3.10 or higher
  • Terminal: Unicode support required
  • OS: Linux, macOS, or Windows (experimental)

πŸ“¦ Installation

From PyPI (Recommended)

pip install selectfilecli

Using uv (Fast Python Package Manager)

uv pip install selectfilecli

From Source

git clone https://github.com/Emasoft/SelectFileCLI.git
cd SelectFileCLI
pip install -e .

Development Installation

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]"

πŸš€ Quick Start

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")

πŸ“– Usage Examples

Basic File Selection (Backward Compatible)

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")

Advanced File Selection with FileInfo

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 πŸ”—'}")

Folder Selection

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)")

Mixed Mode - Files and Folders

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}")

Integration with Click CLI

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()

Configuration File Selector

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

⌨️ Keyboard Controls

Main Navigation

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

Sort Dialog Controls

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

Available Sort Modes

  • 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

πŸ› οΈ Development

Setup Development Environment

# 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

Running Tests

# 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

Code Quality Tools

# 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

Building & Publishing

# Build package
uv build

# Test locally
pip install dist/*.whl

# Publish to PyPI (requires credentials)
uv publish

πŸ”§ Workflows

This project uses GitHub Actions workflows that can be run both locally (via act) and remotely (via GitHub CLI).

Workflow Command Reference

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

Important Notes

  • 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:

🀝 Contributing

Contributions are welcome! Please see our Contributing Guide for details.

Quick Contribution Guide

  1. Fork the repository
  2. Create your feature branch (act create_feature_branch -e '{"inputs":{"branch_name":"amazing-feature"}}')
  3. Commit your changes (act commit -e '{"inputs":{"message":"Add amazing feature"}}')
  4. Push to the branch (act push -e '{"inputs":{"branch":"feature/amazing-feature"}}')
  5. Open a Pull Request (act create_pull_req)

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Copyright (c) 2024 Emasoft

πŸ’¬ Support

πŸ™ Acknowledgments

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!