Clickable file links for Textual applications.
Project description
textual-filelink
Clickable file links for Textual applications. Open files in your editor directly from your TUI.
Features
- 🔗 Clickable file links that open in your preferred editor (VSCode, vim, nano, etc.)
- ☑️ Toggle controls for selecting/deselecting files
- ❌ Remove buttons for file management interfaces
- 🎨 Status icons with unicode support for visual feedback (optionally clickable)
- 🎯 Jump to specific line and column in your editor
- 🔧 Customizable command builders for any editor
- 🎭 Flexible layouts - show/hide controls as needed
- 💬 Tooltips for toggle, status icon, and remove button
Installation
pip install textual-filelink
Or with PDM:
pdm add textual-filelink
Quick Start
Basic FileLink
from pathlib import Path
from textual.app import App, ComposeResult
from textual_filelink import FileLink
class MyApp(App):
def compose(self) -> ComposeResult:
yield FileLink(Path("README.md"), line=10, column=5)
def on_file_link_clicked(self, event: FileLink.Clicked):
self.notify(f"Opened {event.path.name} at line {event.line}")
if __name__ == "__main__":
MyApp().run()
ToggleableFileLink with Status Icons
from textual_filelink import ToggleableFileLink
class MyApp(App):
def compose(self) -> ComposeResult:
yield ToggleableFileLink(
Path("script.py"),
initial_toggle=True,
show_toggle=True,
show_remove=True,
status_icon="✓",
status_icon_clickable=True,
toggle_tooltip="Toggle selection",
status_tooltip="File status",
remove_tooltip="Remove file",
line=42
)
def on_toggleable_file_link_toggled(self, event: ToggleableFileLink.Toggled):
self.notify(f"{event.path.name} toggled: {event.is_toggled}")
def on_toggleable_file_link_removed(self, event: ToggleableFileLink.Removed):
self.notify(f"{event.path.name} removed")
def on_toggleable_file_link_status_icon_clicked(self, event: ToggleableFileLink.StatusIconClicked):
self.notify(f"Status icon '{event.icon}' clicked for {event.path.name}")
if __name__ == "__main__":
MyApp().run()
FileLink API
Constructor
FileLink(
path: Path | str,
*,
line: int | None = None,
column: int | None = None,
command_builder: Callable | None = None,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
)
Parameters:
path: Full path to the fileline: Optional line number to jump tocolumn: Optional column number to jump tocommand_builder: Custom function to build the editor command
Properties
path: Path- The file pathline: int | None- The line numbercolumn: int | None- The column number
Messages
FileLink.Clicked
Posted when the link is clicked.
Attributes:
path: Pathline: int | Nonecolumn: int | None
ToggleableFileLink API
Constructor
ToggleableFileLink(
path: Path | str,
*,
initial_toggle: bool = False,
show_toggle: bool = True,
show_remove: bool = True,
status_icon: str | None = None,
status_icon_clickable: bool = False,
line: int | None = None,
column: int | None = None,
command_builder: Callable | None = None,
disable_on_untoggle: bool = False,
toggle_tooltip: str | None = None,
status_tooltip: str | None = None,
remove_tooltip: str | None = None,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
)
Parameters:
path: Full path to the fileinitial_toggle: Whether the item starts toggled (checked)show_toggle: Whether to display the toggle control (☐/✓)show_remove: Whether to display the remove button (×)status_icon: Optional unicode icon to display before the filenamestatus_icon_clickable: Whether the status icon is clickable (postsStatusIconClickedmessage)line: Optional line number to jump tocolumn: Optional column number to jump tocommand_builder: Custom function to build the editor commanddisable_on_untoggle: If True, dim/disable the link when untoggledtoggle_tooltip: Optional tooltip text for the toggle buttonstatus_tooltip: Optional tooltip text for the status iconremove_tooltip: Optional tooltip text for the remove button
Properties
path: Path- The file pathis_toggled: bool- Current toggle statestatus_icon: str | None- Current status icon
Methods
set_status_icon(icon: str | None, tooltip: str | None = None)
Update the status icon and optionally its tooltip.
link.set_status_icon("⚠", tooltip="Warning: File modified") # Warning
link.set_status_icon("✓", tooltip="Validated") # Success
link.set_status_icon("⏳", tooltip="Processing...") # In progress
link.set_status_icon(None) # Hide icon
set_toggle_tooltip(tooltip: str | None)
Update the toggle button tooltip.
set_remove_tooltip(tooltip: str | None)
Update the remove button tooltip.
Messages
ToggleableFileLink.Toggled
Posted when the toggle state changes.
Attributes:
path: Pathis_toggled: bool
ToggleableFileLink.Removed
Posted when the remove button is clicked.
Attributes:
path: Path
ToggleableFileLink.StatusIconClicked
Posted when the status icon is clicked (if status_icon_clickable=True).
Attributes:
path: Pathicon: str
Custom Editor Commands
Using Built-in Command Builders
from textual_filelink import FileLink
# Set default for all FileLink instances
FileLink.default_command_builder = FileLink.vim_command
# Or per instance
link = FileLink(path, command_builder=FileLink.nano_command)
Available builders:
FileLink.vscode_command- VSCode (default)FileLink.vim_command- VimFileLink.nano_command- NanoFileLink.eclipse_command- EclipseFileLink.copy_path_command- Copy path to clipboard
Custom Command Builder
def my_editor_command(path: Path, line: int | None, column: int | None) -> list[str]:
"""Build command for my custom editor."""
cmd = ["myeditor"]
if line:
cmd.extend(["--line", str(line)])
if column:
cmd.extend(["--column", str(column)])
cmd.append(str(path))
return cmd
link = FileLink(path, command_builder=my_editor_command)
Layout Configurations
Toggle Only
ToggleableFileLink(path, show_toggle=True, show_remove=False)
Display: ☐ filename.txt
Remove Only
ToggleableFileLink(path, show_toggle=False, show_remove=True)
Display: filename.txt ×
Both Controls
ToggleableFileLink(path, show_toggle=True, show_remove=True)
Display: ☐ filename.txt ×
Neither (Plain Link with Status)
ToggleableFileLink(path, show_toggle=False, show_remove=False, status_icon="📄")
Display: 📄 filename.txt
Status Icons
Common unicode icons you can use:
# Status indicators
"✓" # Success/Complete
"⚠" # Warning
"✗" # Error/Failed
"⏳" # In progress
"🔒" # Locked
"📝" # Modified
"➕" # New/Added
"➖" # Deleted
"🔄" # Syncing
# File types
"📄" # Document
"📁" # Folder
"🐍" # Python file
"📊" # Data file
"⚙️" # Config file
Complete Example
from pathlib import Path
from textual.app import App, ComposeResult
from textual.containers import Vertical, Horizontal
from textual.widgets import Header, Footer, Static
from textual_filelink import ToggleableFileLink
class FileManagerApp(App):
CSS = """
Screen {
align: center middle;
}
Vertical {
width: 80;
height: auto;
border: solid green;
padding: 1;
}
Static {
width: 100%;
content-align: center middle;
text-style: bold;
}
"""
def __init__(self):
super().__init__()
self.selected_files = set()
def compose(self) -> ComposeResult:
yield Header()
with Vertical():
yield Static("📁 Project Files")
files = [
("main.py", "✓", True, "Validated", True),
("config.json", "⚠", False, "Needs review", True),
("README.md", "📝", False, "Draft", False),
("tests.py", "⏳", False, "Running tests", False),
]
for filename, icon, toggled, tooltip, clickable in files:
yield ToggleableFileLink(
Path(filename),
initial_toggle=toggled,
show_toggle=True,
show_remove=True,
status_icon=icon,
status_icon_clickable=clickable,
toggle_tooltip="Toggle selection",
status_tooltip=tooltip,
remove_tooltip="Remove file",
line=1,
)
yield Footer()
def on_toggleable_file_link_toggled(self, event: ToggleableFileLink.Toggled):
if event.is_toggled:
self.selected_files.add(event.path)
self.notify(f"✓ Selected {event.path.name}")
else:
self.selected_files.discard(event.path)
self.notify(f"☐ Deselected {event.path.name}")
def on_toggleable_file_link_removed(self, event: ToggleableFileLink.Removed):
self.selected_files.discard(event.path)
# Find and remove the widget
for child in self.query(ToggleableFileLink):
if child.path == event.path:
child.remove()
self.notify(f"❌ Removed {event.path.name}", severity="warning")
def on_toggleable_file_link_status_icon_clicked(self, event: ToggleableFileLink.StatusIconClicked):
self.notify(f"Clicked status icon '{event.icon}' for {event.path.name}")
def on_file_link_clicked(self, event):
self.notify(f"Opening {event.path.name}...")
if __name__ == "__main__":
FileManagerApp().run()
Development
# Clone the repository
git clone https://github.com/eyecantell/textual-filelink.git
cd textual-filelink
# Install with dev dependencies
pdm install -d
# Run tests
pdm run pytest
# Run tests with coverage
pdm run pytest --cov
# Lint
pdm run ruff check .
# Format
pdm run ruff format .
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with Textual by Textualize
- Inspired by the need for better file navigation in terminal applications
Links
- PyPI: https://pypi.org/project/textual-filelink/
- GitHub: https://github.com/eyecantell/textual-filelink
- Issues: https://github.com/eyecantell/textual-filelink/issues
- Textual Documentation: https://textual.textualize.io/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file textual_filelink-0.1.0.tar.gz.
File metadata
- Download URL: textual_filelink-0.1.0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.26.2 CPython/3.10.16 Linux/5.15.167.4-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f20b0a5c68b98d8b7982ab48d8e0bf97f0d86244a1206226b75ac990c4e66ab6
|
|
| MD5 |
27513c495317248a11b7545c88302dd4
|
|
| BLAKE2b-256 |
d7164f2b09e598ab49517d2dcbd5450869c157605ca08a1784a2da81ccbf9a22
|
File details
Details for the file textual_filelink-0.1.0-py3-none-any.whl.
File metadata
- Download URL: textual_filelink-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.26.2 CPython/3.10.16 Linux/5.15.167.4-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
292b22e0aa56e321edc5b544edf00a131f2ce75bcedb68b1a899f3c85669d1ef
|
|
| MD5 |
601fdaf7603d7b8e2f7f49e16d8fb4a6
|
|
| BLAKE2b-256 |
bb64a4f65eab0cbb34d944ef5929a9b5c8c0bb58b5624827cf1dfbd27e7ad6c9
|