mirror of
https://github.com/alexpasmantier/television.git
synced 2025-07-28 13:51:41 +00:00
refactor(cli): add validation logic + docs
This PR contains the following changes - Add validation logic and dependencies - Remove deprecated frame rate - Bump string_pipeline to 0.12.0 (solves debug syntax from templates) - Document cli functionality (markdown and docstrings) --------- Co-authored-by: alexandre pasmantier <alex.pasmant@gmail.com>
This commit is contained in:
parent
601580953a
commit
a2ebbb3557
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -251,10 +251,8 @@ checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
@ -1851,18 +1849,16 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string_pipeline"
|
||||
version = "0.11.1"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0af3613597e31606b54dd5d62be86b8f50922b40d2b7d3d145146caf5c154c05"
|
||||
checksum = "8d7043de9eb4072c03851ec3682a133c26b91b9f8fcc4d52bf911abe2614de12"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap_mangen",
|
||||
"once_cell",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"strip-ansi-escapes",
|
||||
]
|
||||
|
||||
|
@ -54,7 +54,7 @@ lazy-regex = { version = "3.4.1", features = [
|
||||
], default-features = false }
|
||||
ansi-to-tui = "7.0.0"
|
||||
walkdir = "2.5.0"
|
||||
string_pipeline = "0.11.1"
|
||||
string_pipeline = "0.12.0"
|
||||
ureq = "3.0.11"
|
||||
serde_json = "1.0.140"
|
||||
colored = "3.0.0"
|
||||
|
522
docs/cli.md
Normal file
522
docs/cli.md
Normal file
@ -0,0 +1,522 @@
|
||||
# Television CLI Reference
|
||||
|
||||
Television (`tv`) is a cross-platform, fast and extensible general purpose fuzzy finder TUI. This document provides a comprehensive reference for all CLI options, modes, restrictions, and usage patterns.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Operating Modes](#operating-modes)
|
||||
- [Basic Usage](#basic-usage)
|
||||
- [Arguments](#arguments)
|
||||
- [Options](#options)
|
||||
- [Subcommands](#subcommands)
|
||||
- [Flag Dependencies and Restrictions](#flag-dependencies-and-restrictions)
|
||||
- [Configuration](#configuration)
|
||||
- [Template System](#template-system)
|
||||
- [Examples](#examples)
|
||||
- [Advanced Usage](#advanced-usage)
|
||||
|
||||
## Overview
|
||||
|
||||
Television supports two primary operating modes that determine how CLI flags are interpreted and validated:
|
||||
|
||||
1. **Channel Mode**: When a channel is specified, the application uses the channel's configuration as a base and CLI flags act as overrides
|
||||
2. **Ad-hoc Mode**: When no channel is specified, the application creates a custom channel from CLI flags with stricter validation
|
||||
|
||||
## Operating Modes
|
||||
|
||||
### Channel Mode
|
||||
|
||||
**Activated when**: A channel name is provided as the first argument or via `--autocomplete-prompt`
|
||||
|
||||
**Behavior**:
|
||||
- Channel provides base configuration (source commands, preview commands, UI settings)
|
||||
- CLI flags act as **overrides** to channel defaults
|
||||
- More permissive validation - allows most combination of flags
|
||||
- Minimal dependency checking since channel provides sensible defaults
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
tv files --preview-command "bat -n --color=always {}"
|
||||
```
|
||||
|
||||
### Ad-hoc Mode
|
||||
|
||||
**Activated when**: No channel is specified and no `--autocomplete-prompt` is used
|
||||
|
||||
**Behavior**:
|
||||
- Creates a custom channel on-the-fly from CLI flags
|
||||
- Requires `--source-command` to generate any entries
|
||||
- **Stricter validation** ensures necessary components are present
|
||||
- All functionality depends on explicitly provided flags
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
tv --source-command "find . -name '*.rs'" --preview-command "bat -n --color=always {}"
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```
|
||||
tv [OPTIONS] [CHANNEL] [PATH]
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
Television has intelligent positional argument handling with special path detection logic.
|
||||
|
||||
#### Position 1: `[CHANNEL]`
|
||||
**Purpose**: Channel name to activate Channel Mode
|
||||
|
||||
- **Standard behavior**: When a valid channel name is provided, activates Channel Mode
|
||||
- **Special path detection**: If the argument exists as a path on the filesystem, it's automatically treated as a working directory instead
|
||||
- **Effect when path detected**: Switches to Ad-hoc Mode and uses the path as the working directory
|
||||
- **Required**: No (falls back to `default_channel` from the global config)
|
||||
- **Examples**:
|
||||
```bash
|
||||
tv files # Uses 'files' channel
|
||||
tv /home/user/docs # Auto-detects path, uses as working directory
|
||||
tv ./projects # Auto-detects relative path
|
||||
```
|
||||
|
||||
#### Position 2: `[PATH]`
|
||||
**Purpose**: Working directory to start in
|
||||
|
||||
- **Behavior**: Sets the working directory for the application
|
||||
- **Required**: No
|
||||
- **Precedence**: Only used if Position 1 was not detected as a path
|
||||
- **Default**: Current directory
|
||||
- **Example**: `tv files /home/user/projects`
|
||||
|
||||
#### ⚡ Smart Path Detection Logic
|
||||
|
||||
Television automatically detects when the first argument is a filesystem path:
|
||||
|
||||
1. **Path Check**: If Position 1 exists as a file or directory on the filesystem
|
||||
2. **Mode Switch**: Automatically switches to Ad-hoc Mode (no channel)
|
||||
3. **Directory Assignment**: Uses the detected path as the working directory
|
||||
4. **Requirement**: When this happens, `--source-command` becomes required (Ad-hoc Mode rules apply)
|
||||
|
||||
**Examples of Smart Detection**:
|
||||
```bash
|
||||
# No arguments - uses default_channel from config
|
||||
tv
|
||||
|
||||
# Channel name provided - Channel Mode
|
||||
tv files
|
||||
|
||||
# Existing path provided - triggers path detection → uses default_channel
|
||||
tv /home/user/docs # Uses default_channel in /home/user/docs directory
|
||||
|
||||
# Non-existent path - treated as channel name → error if channel doesn't exist
|
||||
tv /nonexistent/path # Error: Channel not found
|
||||
|
||||
# Channel + explicit working directory - Channel Mode
|
||||
tv files /home/user/docs
|
||||
|
||||
# The key nuance: same name, different behavior based on filesystem
|
||||
tv myproject # Channel Mode (if 'myproject' is a channel name)
|
||||
tv ./myproject # Channel Mode with default_channel (if './myproject' directory exists)
|
||||
|
||||
# Ambiguous case - path detection takes precedence
|
||||
tv docs # If 'docs' directory exists → default_channel + path detection
|
||||
# If 'docs' directory doesn't exist → 'docs' channel
|
||||
```
|
||||
|
||||
> **💡 Tip**: This smart detection makes Television intuitive - you can just specify a directory and it automatically knows you want to work in that location.
|
||||
|
||||
## Options
|
||||
|
||||
Television's options are organized by functionality. Each option behaves differently depending on whether you're using Channel Mode (with a channel specified) or Ad-hoc Mode (no channel).
|
||||
|
||||
### 🎯 Source and Data Options
|
||||
|
||||
#### `--source-command <STRING>`
|
||||
**Purpose**: Defines the command that generates entries for the picker
|
||||
|
||||
- **Channel Mode**: Overrides the channel's default source command
|
||||
- **Ad-hoc Mode**: ⚠️ **Required** - without this, no entries will be generated
|
||||
- **Example**: `--source-command "find . -name '*.py'"`
|
||||
|
||||
#### `--source-display <STRING>`
|
||||
**Purpose**: Template for formatting how entries appear in the results list
|
||||
|
||||
- **Channel Mode**: Overrides the channel's display format
|
||||
- **Ad-hoc Mode**: Customize how entries are shown (default: entries as-is)
|
||||
- **Requires**: `--source-command` (in ad-hoc mode)
|
||||
- **Example**: `--source-display "{split:/:-1} ({split:/:0..-1|join:-})"`
|
||||
|
||||
#### `--source-output <STRING>`
|
||||
**Purpose**: Template for formatting the final output when an entry is selected
|
||||
|
||||
- **Channel Mode**: Overrides the channel's output format
|
||||
- **Ad-hoc Mode**: Customize what gets returned (default: entries as-is)
|
||||
- **Requires**: `--source-command` (in ad-hoc mode)
|
||||
- **Example**: `--source-output "code {}"`
|
||||
|
||||
### 👁️ Preview Options
|
||||
|
||||
#### `-p, --preview-command <STRING>`
|
||||
**Purpose**: Command to generate preview content for the selected entry
|
||||
|
||||
- **Channel Mode**: Overrides the channel's preview command
|
||||
- **Ad-hoc Mode**: Enables preview functionality with the specified command
|
||||
- **Requires**: `--source-command` (in ad-hoc mode)
|
||||
- **Conflicts**: Cannot use with `--no-preview`
|
||||
- **Example**: `--preview-command "bat -n --color=always {}"`
|
||||
|
||||
#### `--preview-header <STRING>`
|
||||
**Purpose**: Template for text displayed above the preview panel
|
||||
|
||||
- **Both Modes**: Sets custom header text
|
||||
- **Requires**: `--preview-command` (in ad-hoc mode)
|
||||
- **Conflicts**: Cannot use with `--no-preview`
|
||||
- **Example**: `--preview-header "File: {split:/:-1|upper}"`
|
||||
|
||||
#### `--preview-footer <STRING>`
|
||||
**Purpose**: Template for text displayed below the preview panel
|
||||
|
||||
- **Both Modes**: Sets custom footer text
|
||||
- **Requires**: `--preview-command` (in ad-hoc mode)
|
||||
- **Conflicts**: Cannot use with `--no-preview`
|
||||
|
||||
#### `--preview-offset <STRING>`
|
||||
**Purpose**: Template that determines the scroll position in the preview
|
||||
|
||||
- **Both Modes**: Controls where preview content starts displaying
|
||||
- **Requires**: `--preview-command` (in ad-hoc mode)
|
||||
- **Conflicts**: Cannot use with `--no-preview`
|
||||
- **Example**: `--preview-offset "10"` (start at line 10)
|
||||
|
||||
#### `--preview-size <INTEGER>`
|
||||
**Purpose**: Width of the preview panel as a percentage
|
||||
|
||||
- **Both Modes**: Controls preview panel size
|
||||
- **Default**: 50% of screen width
|
||||
- **Range**: 1-99
|
||||
- **Conflicts**: Cannot use with `--no-preview`
|
||||
|
||||
#### `--no-preview`
|
||||
**Purpose**: Completely disables the preview panel
|
||||
|
||||
- **Both Modes**: Turns off all preview functionality
|
||||
- **Conflicts**: Cannot use with any `--preview-*` flags
|
||||
- **Use Case**: Faster performance, simpler interface
|
||||
|
||||
### 🎨 Interface and Layout Options
|
||||
|
||||
#### `--layout <LAYOUT>`
|
||||
**Purpose**: Controls the overall interface orientation
|
||||
|
||||
- **Channel Mode**: Overrides channel's layout setting
|
||||
- **Ad-hoc Mode**: Sets interface layout
|
||||
- **Values**: `landscape` (side-by-side), `portrait` (stacked)
|
||||
- **Default**: `landscape`
|
||||
|
||||
#### `--input-header <STRING>`
|
||||
**Purpose**: Template for text displayed above the input field
|
||||
|
||||
- **Channel Mode**: Overrides channel's input header
|
||||
- **Ad-hoc Mode**: Sets custom input header
|
||||
- **Default**: Channel name (channel mode) or empty (ad-hoc mode)
|
||||
- **Example**: `--input-header "Search files:"`
|
||||
|
||||
#### `--ui-scale <INTEGER>`
|
||||
**Purpose**: Scales the entire interface size
|
||||
|
||||
- **Both Modes**: Adjusts display size as a percentage
|
||||
- **Default**: 100%
|
||||
- **Range**: 10-100%
|
||||
- **Use Case**: Adapt to different screen sizes or preferences
|
||||
|
||||
#### `--no-help`
|
||||
**Purpose**: Hides the help panel showing keyboard shortcuts
|
||||
|
||||
- **Both Modes**: Removes help information from display
|
||||
- **Use Case**: More screen space, cleaner interface for experienced users
|
||||
|
||||
#### `--no-remote`
|
||||
**Purpose**: Hides the remote control panel
|
||||
|
||||
- **Both Modes**: Removes remote control information from display
|
||||
- **Use Case**: Simpler interface when remote features aren't needed
|
||||
|
||||
### ⌨️ Input and Interaction Options
|
||||
|
||||
#### `-i, --input <STRING>`
|
||||
**Purpose**: Pre-fills the input prompt with specified text
|
||||
|
||||
- **Both Modes**: Starts with text already in the search box
|
||||
- **Use Case**: Continue a previous search or provide default query
|
||||
- **Example**: `-i "main.py"`
|
||||
|
||||
#### `-k, --keybindings <STRING>`
|
||||
**Purpose**: Overrides default keyboard shortcuts
|
||||
|
||||
- **Both Modes**: Customizes key bindings for actions
|
||||
- **Format**: `action1=["key1","key2"];action2=["key3"]`
|
||||
- **Example**: `-k 'quit=["q","esc"];select=["enter","space"]'`
|
||||
|
||||
#### `--exact`
|
||||
**Purpose**: Changes matching behavior from fuzzy to exact substring matching
|
||||
|
||||
- **Channel Mode**: Overrides channel's matching mode
|
||||
- **Ad-hoc Mode**: Enables exact matching
|
||||
- **Default**: Fuzzy matching
|
||||
- **Use Case**: When you need precise substring matches
|
||||
|
||||
### ⚡ Selection Behavior Options
|
||||
|
||||
> **Note**: These options are mutually exclusive - only one can be used at a time.
|
||||
|
||||
#### `--select-1`
|
||||
**Purpose**: Automatically selects and returns the entry if only one is found
|
||||
|
||||
- **Both Modes**: Bypasses interactive selection when there's only one match
|
||||
- **Use Case**: Scripting scenarios where single results should be auto-selected
|
||||
|
||||
#### `--take-1`
|
||||
**Purpose**: Takes the first entry after loading completes
|
||||
|
||||
- **Both Modes**: Automatically selects first item once all entries are loaded
|
||||
- **Use Case**: Scripts that always want the first/best result
|
||||
|
||||
#### `--take-1-fast`
|
||||
**Purpose**: Takes the first entry immediately as it appears
|
||||
|
||||
- **Both Modes**: Selects first item as soon as it's available
|
||||
- **Use Case**: Maximum speed scripts that don't care about all options
|
||||
|
||||
### ⚙️ Performance and Monitoring Options
|
||||
|
||||
#### `-t, --tick-rate <FLOAT>`
|
||||
**Purpose**: Controls how frequently the interface updates (times per second)
|
||||
|
||||
- **Both Modes**: Sets UI refresh rate
|
||||
- **Default**: Auto-calculated based on system performance
|
||||
- **Validation**: Must be positive number
|
||||
- **Example**: `--tick-rate 30` (30 updates per second)
|
||||
|
||||
#### `--watch <FLOAT>`
|
||||
**Purpose**: Automatically re-runs the source command at regular intervals
|
||||
|
||||
- **Channel Mode**: Overrides channel's watch interval
|
||||
- **Ad-hoc Mode**: Enables live monitoring mode
|
||||
- **Default**: 0 (disabled)
|
||||
- **Units**: Seconds between updates
|
||||
- **Conflicts**: Cannot use with selection options (`--select-1`, `--take-1`, `--take-1-fast`)
|
||||
- **Example**: `--watch 2.0` (update every 2 seconds)
|
||||
|
||||
### 📁 Directory and Configuration Options
|
||||
|
||||
#### `[PATH]` (Positional Argument 2)
|
||||
**Purpose**: Sets the working directory for the command
|
||||
|
||||
- **Both Modes**: Changes to specified directory before running
|
||||
- **Default**: Current directory
|
||||
- **Example**: `tv files /home/user/projects`
|
||||
|
||||
#### `--config-file <PATH>`
|
||||
**Purpose**: Uses a custom configuration file instead of the default
|
||||
|
||||
- **Both Modes**: Loads settings from specified file
|
||||
- **Default**: `~/.config/tv/config.toml` (Linux/macOS) or `%APPDATA%\tv\config.toml` (Windows)
|
||||
- **Use Case**: Multiple configurations for different workflows
|
||||
|
||||
#### `--cable-dir <PATH>`
|
||||
**Purpose**: Uses a custom directory for channel definitions
|
||||
|
||||
- **Both Modes**: Loads channels from specified directory
|
||||
- **Default**: `~/.config/tv/cable/` (Linux/macOS) or `%APPDATA%\tv\cable\` (Windows)
|
||||
- **Use Case**: Custom channel collections or shared team channels
|
||||
|
||||
### 🔧 Special Mode Options
|
||||
|
||||
#### `--autocomplete-prompt <STRING>`
|
||||
**Purpose**: ⚡ **Activates Channel Mode** - Auto-detects channel from shell command
|
||||
|
||||
- **Effect**: Switches to Channel Mode automatically
|
||||
- **Behavior**: Analyzes the provided command to determine appropriate channel
|
||||
- **Conflicts**: Cannot use with `[CHANNEL]` positional argument
|
||||
- **Use Case**: Shell integration and smart channel detection
|
||||
- **Example**: `--autocomplete-prompt "git log --oneline"`
|
||||
|
||||
## Subcommands
|
||||
|
||||
### `list-channels`
|
||||
Lists all available channels in the cable directory.
|
||||
|
||||
```bash
|
||||
tv list-channels
|
||||
```
|
||||
|
||||
### `init <SHELL>`
|
||||
Generates shell completion script for the specified shell.
|
||||
|
||||
**Supported shells**: `bash`, `zsh`, `fish`, `powershell`, `cmd`
|
||||
|
||||
```bash
|
||||
tv init zsh > ~/.zshrc.d/tv-completion.zsh
|
||||
```
|
||||
|
||||
### `update-channels`
|
||||
Downloads the latest channel prototypes from GitHub.
|
||||
|
||||
```bash
|
||||
tv update-channels
|
||||
```
|
||||
|
||||
## Usage Rules and Restrictions
|
||||
|
||||
> **Note**: Detailed requirements and conflicts for each flag are covered in the [Options](#options) section above. This section provides a high-level overview of the key rules.
|
||||
|
||||
### 🎯 Ad-hoc Mode Requirements
|
||||
|
||||
When using Television without a channel, certain flags become mandatory:
|
||||
|
||||
- **`--source-command` is required** - without this, no entries will be generated
|
||||
- **Preview dependencies** - all `--preview-*` flags require `--preview-command` to be functional
|
||||
- **Source formatting dependencies** - `--source-display` and `--source-output` require `--source-command`
|
||||
|
||||
### 🚫 Mutually Exclusive Options
|
||||
|
||||
These option groups cannot be used together:
|
||||
|
||||
- **Selection behavior**: Only one of `--select-1`, `--take-1`, or `--take-1-fast`
|
||||
- **Preview control**: `--no-preview` conflicts with all `--preview-*` flags
|
||||
- **Channel selection**: Cannot use both `[CHANNEL]` argument and `--autocomplete-prompt`
|
||||
- **Watch vs selection**: `--watch` cannot be used with auto-selection flags
|
||||
|
||||
### ✅ Channel Mode Benefits
|
||||
|
||||
Channels provide sensible defaults, making the tool more flexible:
|
||||
- Preview and source flags work independently (channel provides missing pieces)
|
||||
- All UI options have reasonable defaults
|
||||
- Less strict validation since channels fill in the gaps
|
||||
|
||||
## Configuration
|
||||
|
||||
### ⚡ Configuration Priority
|
||||
|
||||
Television uses a layered configuration system where each layer can override the previous:
|
||||
|
||||
1. **CLI flags** - Highest priority, overrides everything
|
||||
2. **Channel configuration** - Channel-specific settings
|
||||
3. **User config file** - Personal preferences
|
||||
4. **Built-in defaults** - Fallback values
|
||||
|
||||
### 📁 Configuration Locations
|
||||
|
||||
#### User Configuration File
|
||||
- **Linux/macOS**: `~/.config/tv/config.toml`
|
||||
- **Windows**: `%APPDATA%\tv\config.toml`
|
||||
|
||||
#### Channel Definitions (Cable Directory)
|
||||
- **Linux/macOS**: `~/.config/tv/cable/`
|
||||
- **Windows**: `%APPDATA%\tv\cable\`
|
||||
|
||||
> **Tip**: Use `--config-file` and `--cable-dir` flags to override these default locations
|
||||
|
||||
## Template System
|
||||
|
||||
Television uses a powerful template system for dynamic content generation. Templates are enclosed in curly braces `{}` and support complex operations.
|
||||
|
||||
### Template-Enabled Flags
|
||||
|
||||
| Flag Category | Flags Using Templates |
|
||||
|---------------|----------------------|
|
||||
| **Source** | `--source-command`, `--source-display`, `--source-output` |
|
||||
| **Preview** | `--preview-command`, `--preview-offset` |
|
||||
| **Headers** | `--input-header`, `--preview-header`, `--preview-footer` |
|
||||
|
||||
### Basic Template Syntax
|
||||
|
||||
Templates support a wide range of operations that can be chained together:
|
||||
|
||||
```text
|
||||
{operation1|operation2|operation3}
|
||||
```
|
||||
|
||||
### Core Template Operations
|
||||
|
||||
| Operation | Description | Example |
|
||||
|-----------|-------------|---------|
|
||||
| `{}` | Full entry (passthrough) | `{}` → original entry |
|
||||
| `{split:SEPARATOR:RANGE}` | Split text and extract parts | `{split:/:‑1}` → last path component |
|
||||
| `{upper}` | Convert to uppercase | `{upper}` → "HELLO" |
|
||||
| `{lower}` | Convert to lowercase | `{lower}` → "hello" |
|
||||
| `{trim}` | Remove whitespace | `{trim}` → "text" |
|
||||
| `{append:TEXT}` | Add text to end | `{append:.txt}` → "file.txt" |
|
||||
| `{prepend:TEXT}` | Add text to beginning | `{prepend:/home/}` → "/home/file" |
|
||||
|
||||
### Advanced Template Operations
|
||||
|
||||
| Operation | Description | Example |
|
||||
|-----------|-------------|---------|
|
||||
| `{replace:s/PATTERN/REPLACEMENT/FLAGS}` | Regex find and replace | `{replace:s/\\.py$/.backup/}` |
|
||||
| `{regex_extract:PATTERN}` | Extract matching text | `{regex_extract:\\d+}` → extract numbers |
|
||||
| `{filter:PATTERN}` | Keep items matching pattern | `{split:,:..\|filter:^test}` |
|
||||
| `{sort}` | Sort list items | `{split:,:..\|sort}` |
|
||||
| `{unique}` | Remove duplicates | `{split:,:..\|unique}` |
|
||||
| `{join:SEPARATOR}` | Join list with separator | `{split:,:..\|join:-}` |
|
||||
|
||||
### Template Examples
|
||||
|
||||
```text
|
||||
# File path manipulation
|
||||
{split:/:-1} # Get filename from path
|
||||
{split:/:0..-1|join:/} # Get directory from path
|
||||
|
||||
# Text processing
|
||||
{split: :..|map:{upper}|join:_} # "hello world" → "HELLO_WORLD"
|
||||
{trim|replace:s/\s+/_/g} # Replace spaces with underscores
|
||||
|
||||
# Data extraction
|
||||
{regex_extract:@(.+)} # Extract email domain
|
||||
{split:,:..|filter:^[A-Z]} # Filter items starting with uppercase
|
||||
```
|
||||
|
||||
### Range Specifications
|
||||
|
||||
| Syntax | Description |
|
||||
|--------|-------------|
|
||||
| `N` | Single index (0-based) |
|
||||
| `N..M` | Range exclusive (items N to M-1) |
|
||||
| `N..=M` | Range inclusive (items N to M) |
|
||||
| `N..` | From N to end |
|
||||
| `..M` | From start to M-1 |
|
||||
| `..` | All items |
|
||||
| `-1` | Last item |
|
||||
| `-N` | N-th from end |
|
||||
|
||||
|
||||
For complete template documentation, see the [Template System Documentation](https://github.com/lalvarezt/string_pipeline/blob/main/docs/template-system.md).
|
||||
|
||||
## Examples
|
||||
|
||||
> **Note**: More detailed examples with explanations are included in each option's documentation above.
|
||||
|
||||
### 🎯 Quick Start Examples
|
||||
|
||||
#### Channel Mode (Recommended)
|
||||
```bash
|
||||
# Basic usage - use built-in channels
|
||||
tv files # Browse files in current directory
|
||||
tv git-log # Browse git commit history
|
||||
tv docker-images # Browse Docker images
|
||||
|
||||
# Channel + customization
|
||||
tv files --preview-command "bat -n --color=always {}"
|
||||
tv git-log --layout portrait
|
||||
```
|
||||
|
||||
#### Ad-hoc Mode (Custom Commands)
|
||||
```bash
|
||||
# Simple custom finder
|
||||
tv --source-command "find . -name '*.md'"
|
||||
|
||||
# Live system monitoring
|
||||
tv --source-command "ps aux | tail -n +2" \
|
||||
--watch 1.0 \
|
||||
--no-preview
|
||||
```
|
98
man/tv.1
98
man/tv.1
@ -4,7 +4,7 @@
|
||||
.SH NAME
|
||||
television \- A cross\-platform, fast and extensible general purpose fuzzy finder TUI.
|
||||
.SH SYNOPSIS
|
||||
\fBtelevision\fR [\fB\-\-preview\-offset\fR] [\fB\-\-no\-preview\fR] [\fB\-t\fR|\fB\-\-tick\-rate\fR] [\fB\-f\fR|\fB\-\-frame\-rate\fR] [\fB\-k\fR|\fB\-\-keybindings\fR] [\fB\-i\fR|\fB\-\-input\fR] [\fB\-\-input\-header\fR] [\fB\-\-preview\-header\fR] [\fB\-\-preview\-footer\fR] [\fB\-\-source\-command\fR] [\fB\-\-source\-display\fR] [\fB\-\-source\-output\fR] [\fB\-p\fR|\fB\-\-preview\-command\fR] [\fB\-\-layout\fR] [\fB\-\-autocomplete\-prompt\fR] [\fB\-\-exact\fR] [\fB\-\-select\-1\fR] [\fB\-\-take\-1\fR] [\fB\-\-take\-1\-fast\fR] [\fB\-\-no\-remote\fR] [\fB\-\-no\-help\fR] [\fB\-\-ui\-scale\fR] [\fB\-\-preview\-size\fR] [\fB\-\-config\-file\fR] [\fB\-\-cable\-dir\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fICHANNEL\fR] [\fIPATH\fR] [\fIsubcommands\fR]
|
||||
\fBtelevision\fR [\fB\-\-preview\-offset\fR] [\fB\-\-no\-preview\fR] [\fB\-t\fR|\fB\-\-tick\-rate\fR] [\fB\-\-watch\fR] [\fB\-k\fR|\fB\-\-keybindings\fR] [\fB\-i\fR|\fB\-\-input\fR] [\fB\-\-input\-header\fR] [\fB\-\-preview\-header\fR] [\fB\-\-preview\-footer\fR] [\fB\-\-source\-command\fR] [\fB\-\-source\-display\fR] [\fB\-\-source\-output\fR] [\fB\-p\fR|\fB\-\-preview\-command\fR] [\fB\-\-layout\fR] [\fB\-\-autocomplete\-prompt\fR] [\fB\-\-exact\fR] [\fB\-\-select\-1\fR] [\fB\-\-take\-1\fR] [\fB\-\-take\-1\-fast\fR] [\fB\-\-no\-remote\fR] [\fB\-\-no\-help\fR] [\fB\-\-ui\-scale\fR] [\fB\-\-preview\-size\fR] [\fB\-\-config\-file\fR] [\fB\-\-cable\-dir\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fICHANNEL\fR] [\fIPATH\fR] [\fIsubcommands\fR]
|
||||
.SH DESCRIPTION
|
||||
A cross\-platform, fast and extensible general purpose fuzzy finder TUI.
|
||||
.SH OPTIONS
|
||||
@ -13,29 +13,45 @@ A cross\-platform, fast and extensible general purpose fuzzy finder TUI.
|
||||
A preview line number offset template to use to scroll the preview to for each
|
||||
entry.
|
||||
|
||||
When a channel is specified: This overrides the offset defined in the channel prototype.
|
||||
When no channel is specified: This flag requires \-\-preview\-command to be set.
|
||||
|
||||
This template uses the same syntax as the `preview` option and will be formatted
|
||||
using the currently selected entry.
|
||||
.TP
|
||||
\fB\-\-no\-preview\fR
|
||||
Disable the preview panel entirely on startup.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
When set, no preview panel will be shown regardless of channel configuration
|
||||
or preview\-related flags.
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-tick\-rate\fR=\fIFLOAT\fR
|
||||
The application\*(Aqs tick rate.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
The tick rate is the number of times the application will update per
|
||||
second. This can be used to control responsiveness and CPU usage on
|
||||
very slow machines or very fast ones but the default should be a good
|
||||
compromise for most users.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-frame\-rate\fR=\fIFLOAT\fR
|
||||
[DEPRECATED] Frame rate, i.e. number of frames to render per second.
|
||||
\fB\-\-watch\fR=\fIFLOAT\fR
|
||||
Watch mode: reload the source command every N seconds.
|
||||
|
||||
This option is deprecated and will be removed in a future release.
|
||||
When a channel is specified: Overrides the watch interval defined in the channel prototype.
|
||||
When no channel is specified: Sets the watch interval for the ad\-hoc channel.
|
||||
|
||||
When set to a positive number, the application will automatically
|
||||
reload the source command at the specified interval. This is useful
|
||||
for monitoring changing data sources. Set to 0 to disable (default).
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-keybindings\fR=\fISTRING\fR
|
||||
Keybindings to override the default keybindings.
|
||||
|
||||
This can be used to override the default keybindings with a custom subset
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This can be used to override the default keybindings with a custom subset.
|
||||
The keybindings are specified as a semicolon separated list of keybinding
|
||||
expressions using the configuration file formalism.
|
||||
|
||||
@ -44,12 +60,17 @@ Example: `tv \-\-keybindings=\*(Aqquit="esc";select_next_entry=["down","ctrl\-j"
|
||||
\fB\-i\fR, \fB\-\-input\fR=\fISTRING\fR
|
||||
Input text to pass to the channel to prefill the prompt.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This can be used to provide a default value for the prompt upon
|
||||
startup.
|
||||
.TP
|
||||
\fB\-\-input\-header\fR=\fISTRING\fR
|
||||
Input field header template.
|
||||
|
||||
When a channel is specified: Overrides the input header defined in the channel prototype.
|
||||
When no channel is specified: Sets the input header for the ad\-hoc channel.
|
||||
|
||||
The given value is parsed as a `MultiTemplate`. It is evaluated against
|
||||
the current channel name and the resulting text is shown as the input
|
||||
field title. Defaults to the current channel name when omitted.
|
||||
@ -57,39 +78,53 @@ field title. Defaults to the current channel name when omitted.
|
||||
\fB\-\-preview\-header\fR=\fISTRING\fR
|
||||
Preview header template
|
||||
|
||||
When a channel is specified: This overrides the header defined in the channel prototype.
|
||||
When no channel is specified: This flag requires \-\-preview\-command to be set.
|
||||
|
||||
The given value is parsed as a `MultiTemplate`. It is evaluated for every
|
||||
entry and its result is displayed above the preview panel.
|
||||
.TP
|
||||
\fB\-\-preview\-footer\fR=\fISTRING\fR
|
||||
Preview footer template
|
||||
|
||||
When a channel is specified: This overrides the footer defined in the channel prototype.
|
||||
When no channel is specified: This flag requires \-\-preview\-command to be set.
|
||||
|
||||
The given value is parsed as a `MultiTemplate`. It is evaluated for every
|
||||
entry and its result is displayed below the preview panel.
|
||||
.TP
|
||||
\fB\-\-source\-command\fR=\fISTRING\fR
|
||||
Source command to use for the current channel.
|
||||
|
||||
This overrides the command defined in the channel prototype.
|
||||
When a channel is specified: This overrides the command defined in the channel prototype.
|
||||
When no channel is specified: This creates an ad\-hoc channel with the given command.
|
||||
|
||||
Example: `find . \-name \*(Aq*.rs\*(Aq`
|
||||
.TP
|
||||
\fB\-\-source\-display\fR=\fISTRING\fR
|
||||
Source display template to use for the current channel.
|
||||
|
||||
This overrides the display template defined in the channel prototype.
|
||||
When a channel is specified: This overrides the display template defined in the channel prototype.
|
||||
When no channel is specified: This flag requires \-\-source\-command to be set.
|
||||
|
||||
The template is used to format each entry in the results list.
|
||||
Example: `{split:/:\-1}` (show only the last path segment)
|
||||
.TP
|
||||
\fB\-\-source\-output\fR=\fISTRING\fR
|
||||
Source output template to use for the current channel.
|
||||
|
||||
This overrides the output template defined in the channel prototype.
|
||||
When a channel is specified: This overrides the output template defined in the channel prototype.
|
||||
When no channel is specified: This flag requires \-\-source\-command to be set.
|
||||
|
||||
The template is used to format the final output when an entry is selected.
|
||||
Example: "{}" (output the full entry)
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-preview\-command\fR=\fISTRING\fR
|
||||
Preview command to use for the current channel.
|
||||
|
||||
This overrides the preview command defined in the channel prototype.
|
||||
When a channel is specified: This overrides the preview command defined in the channel prototype.
|
||||
When no channel is specified: This enables preview functionality for the ad\-hoc channel.
|
||||
|
||||
Example: "cat {}" (where {} will be replaced with the entry)
|
||||
|
||||
Parts of the entry can be extracted positionally using the `delimiter`
|
||||
@ -97,15 +132,24 @@ option.
|
||||
Example: "echo {0} {1}" will split the entry by the delimiter and pass
|
||||
the first two fields to the command.
|
||||
.TP
|
||||
\fB\-\-layout\fR=\fISTRING\fR
|
||||
\fB\-\-layout\fR=\fILAYOUT\fR
|
||||
Layout orientation for the UI.
|
||||
|
||||
This overrides the layout/orientation defined in the channel prototype.
|
||||
When a channel is specified: Overrides the layout/orientation defined in the channel prototype.
|
||||
When no channel is specified: Sets the layout orientation for the ad\-hoc channel.
|
||||
|
||||
Options are "landscape" or "portrait".
|
||||
.br
|
||||
|
||||
.br
|
||||
[\fIpossible values: \fRlandscape, portrait]
|
||||
.TP
|
||||
\fB\-\-autocomplete\-prompt\fR=\fISTRING\fR
|
||||
Try to guess the channel from the provided input prompt.
|
||||
|
||||
This flag automatically selects channel mode by guessing the appropriate channel.
|
||||
It conflicts with manually specifying a channel since it determines the channel automatically.
|
||||
|
||||
This can be used to automatically select a channel based on the input
|
||||
prompt by using the `shell_integration` mapping in the configuration
|
||||
file.
|
||||
@ -113,6 +157,8 @@ file.
|
||||
\fB\-\-exact\fR
|
||||
Use substring matching instead of fuzzy matching.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will use substring matching instead of fuzzy matching when
|
||||
searching for entries. This is useful when the user wants to search for
|
||||
an exact match instead of a fuzzy match e.g. to improve performance.
|
||||
@ -121,6 +167,8 @@ an exact match instead of a fuzzy match e.g. to improve performance.
|
||||
Automatically select and output the first entry if there is only one
|
||||
entry.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
Note that most channels stream entries asynchronously which means that
|
||||
knowing if there\*(Aqs only one entry will require waiting for the channel
|
||||
to finish loading first.
|
||||
@ -131,6 +179,8 @@ loading times are usually very short and will go unnoticed by the user.
|
||||
\fB\-\-take\-1\fR
|
||||
Take the first entry from the list after the channel has finished loading.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will wait for the channel to finish loading all entries and then
|
||||
automatically select and output the first entry. Unlike `select_1`, this
|
||||
will always take the first entry regardless of how many entries are available.
|
||||
@ -138,6 +188,8 @@ will always take the first entry regardless of how many entries are available.
|
||||
\fB\-\-take\-1\-fast\fR
|
||||
Take the first entry from the list as soon as it becomes available.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will immediately select and output the first entry as soon as it
|
||||
appears in the results, without waiting for the channel to finish loading.
|
||||
This is the fastest option when you just want the first result.
|
||||
@ -145,6 +197,8 @@ This is the fastest option when you just want the first result.
|
||||
\fB\-\-no\-remote\fR
|
||||
Disable the remote control.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will disable the remote control panel and associated actions
|
||||
entirely. This is useful when the remote control is not needed or
|
||||
when the user wants `tv` to run in single\-channel mode (e.g. when
|
||||
@ -154,6 +208,8 @@ application).
|
||||
\fB\-\-no\-help\fR
|
||||
Disable the help panel.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will disable the help panel and associated toggling actions
|
||||
entirely. This is useful when the help panel is not needed or
|
||||
when the user wants `tv` to run with a minimal interface (e.g. when
|
||||
@ -163,19 +219,26 @@ application).
|
||||
\fB\-\-ui\-scale\fR=\fIINTEGER\fR [default: 100]
|
||||
Change the display size in relation to the available area.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This will crop the UI to a centered rectangle of the specified
|
||||
percentage of the available area (e.g. 0.5 for 50% x 50%).
|
||||
percentage of the available area.
|
||||
.TP
|
||||
\fB\-\-preview\-size\fR=\fIINTEGER\fR
|
||||
Percentage of the screen to allocate to the preview panel (1\-99).
|
||||
|
||||
This value overrides any `preview_size` defined in configuration files or channel prototypes.
|
||||
When a channel is specified: This overrides any `preview_size` defined in configuration files or channel prototypes.
|
||||
When no channel is specified: This flag requires \-\-preview\-command to be set.
|
||||
.TP
|
||||
\fB\-\-config\-file\fR=\fIPATH\fR
|
||||
Provide a custom configuration file to use.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
.TP
|
||||
\fB\-\-cable\-dir\fR=\fIPATH\fR
|
||||
Provide a custom cable directory to use.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Print help (see a summary with \*(Aq\-h\*(Aq)
|
||||
@ -186,6 +249,13 @@ Print version
|
||||
[\fICHANNEL\fR]
|
||||
Which channel shall we watch?
|
||||
|
||||
When specified: The application operates in \*(Aqchannel mode\*(Aq where the selected
|
||||
channel provides the base configuration, and CLI flags act as overrides.
|
||||
|
||||
When omitted: The application operates in \*(Aqad\-hoc mode\*(Aq where you must provide
|
||||
at least \-\-source\-command to create a custom channel. In this mode, preview
|
||||
and source flags have stricter validation rules.
|
||||
|
||||
A list of the available channels can be displayed using the
|
||||
`list\-channels` command. The channel can also be changed from within
|
||||
the application.
|
||||
@ -193,6 +263,8 @@ the application.
|
||||
[\fIPATH\fR]
|
||||
The working directory to start the application in.
|
||||
|
||||
This flag works identically in both channel mode and ad\-hoc mode.
|
||||
|
||||
This can be used to specify a different working directory for the
|
||||
application to start in. This is useful when the application is
|
||||
started from a different directory than the one the user wants to
|
||||
|
@ -1,55 +1,92 @@
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
|
||||
/// Television CLI arguments structure.
|
||||
///
|
||||
/// This CLI supports two primary modes of operation:
|
||||
///
|
||||
/// # Channel Mode (when `channel` is specified)
|
||||
/// In this mode, the specified channel provides base configuration (source commands,
|
||||
/// preview commands, UI settings, etc.) and CLI flags act as **overrides** to those defaults.
|
||||
/// This mode is more permissive and allows any combination of flags since they override
|
||||
/// sensible channel defaults.
|
||||
///
|
||||
/// # Ad-hoc Mode (when `channel` is not specified)
|
||||
/// In this mode, the CLI creates a custom channel on-the-fly based on the provided flags.
|
||||
/// This mode has **stricter validation** to ensure the resulting channel is functional:
|
||||
/// - Source-related flags (`--source-display`, `--source-output`) require `--source-command`
|
||||
/// - Preview-related flags (`--preview-*`) require `--preview-command`
|
||||
///
|
||||
/// This validation prevents creating broken ad-hoc channels that reference non-existent commands.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Parser, Debug, Default)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Which channel shall we watch?
|
||||
///
|
||||
/// When specified: The application operates in 'channel mode' where the selected
|
||||
/// channel provides the base configuration, and CLI flags act as overrides.
|
||||
///
|
||||
/// When omitted: The application operates in 'ad-hoc mode' where you must provide
|
||||
/// at least --source-command to create a custom channel. In this mode, preview
|
||||
/// and source flags have stricter validation rules.
|
||||
///
|
||||
/// A list of the available channels can be displayed using the
|
||||
/// `list-channels` command. The channel can also be changed from within
|
||||
/// the application.
|
||||
#[arg(value_enum, index = 1, verbatim_doc_comment)]
|
||||
#[arg(
|
||||
value_enum,
|
||||
index = 1,
|
||||
verbatim_doc_comment,
|
||||
conflicts_with = "autocomplete_prompt"
|
||||
)]
|
||||
pub channel: Option<String>,
|
||||
|
||||
/// A preview line number offset template to use to scroll the preview to for each
|
||||
/// entry.
|
||||
///
|
||||
/// When a channel is specified: This overrides the offset defined in the channel prototype.
|
||||
/// When no channel is specified: This flag requires --preview-command to be set.
|
||||
///
|
||||
/// This template uses the same syntax as the `preview` option and will be formatted
|
||||
/// using the currently selected entry.
|
||||
#[arg(long, value_name = "STRING", verbatim_doc_comment)]
|
||||
pub preview_offset: Option<String>,
|
||||
|
||||
/// Disable the preview panel entirely on startup.
|
||||
#[arg(long, default_value = "false", verbatim_doc_comment)]
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
/// When set, no preview panel will be shown regardless of channel configuration
|
||||
/// or preview-related flags.
|
||||
#[arg(long, default_value = "false", verbatim_doc_comment, conflicts_with_all = ["preview_offset", "preview_header", "preview_footer", "preview_size", "preview_command"])]
|
||||
pub no_preview: bool,
|
||||
|
||||
/// The application's tick rate.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// The tick rate is the number of times the application will update per
|
||||
/// second. This can be used to control responsiveness and CPU usage on
|
||||
/// very slow machines or very fast ones but the default should be a good
|
||||
/// compromise for most users.
|
||||
#[arg(short, long, value_name = "FLOAT", verbatim_doc_comment)]
|
||||
#[arg(short, long, value_name = "FLOAT", verbatim_doc_comment, value_parser = validate_positive_float)]
|
||||
pub tick_rate: Option<f64>,
|
||||
|
||||
/// Watch mode: reload the source command every N seconds.
|
||||
///
|
||||
/// When a channel is specified: Overrides the watch interval defined in the channel prototype.
|
||||
/// When no channel is specified: Sets the watch interval for the ad-hoc channel.
|
||||
///
|
||||
/// When set to a positive number, the application will automatically
|
||||
/// reload the source command at the specified interval. This is useful
|
||||
/// for monitoring changing data sources. Set to 0 to disable (default).
|
||||
#[arg(long, value_name = "FLOAT", verbatim_doc_comment)]
|
||||
#[arg(long, value_name = "FLOAT", verbatim_doc_comment, value_parser = validate_non_negative_float, conflicts_with_all = ["select_1", "take_1", "take_1_fast"])]
|
||||
pub watch: Option<f64>,
|
||||
|
||||
/// [DEPRECATED] Frame rate, i.e. number of frames to render per second.
|
||||
///
|
||||
/// This option is deprecated and will be removed in a future release.
|
||||
#[arg(short, long, value_name = "FLOAT", verbatim_doc_comment)]
|
||||
pub frame_rate: Option<f64>,
|
||||
|
||||
/// Keybindings to override the default keybindings.
|
||||
///
|
||||
/// This can be used to override the default keybindings with a custom subset
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This can be used to override the default keybindings with a custom subset.
|
||||
/// The keybindings are specified as a semicolon separated list of keybinding
|
||||
/// expressions using the configuration file formalism.
|
||||
///
|
||||
@ -59,6 +96,8 @@ pub struct Cli {
|
||||
|
||||
/// Input text to pass to the channel to prefill the prompt.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This can be used to provide a default value for the prompt upon
|
||||
/// startup.
|
||||
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
|
||||
@ -66,6 +105,9 @@ pub struct Cli {
|
||||
|
||||
/// Input field header template.
|
||||
///
|
||||
/// When a channel is specified: Overrides the input header defined in the channel prototype.
|
||||
/// When no channel is specified: Sets the input header for the ad-hoc channel.
|
||||
///
|
||||
/// The given value is parsed as a `MultiTemplate`. It is evaluated against
|
||||
/// the current channel name and the resulting text is shown as the input
|
||||
/// field title. Defaults to the current channel name when omitted.
|
||||
@ -74,29 +116,39 @@ pub struct Cli {
|
||||
|
||||
/// Preview header template
|
||||
///
|
||||
/// When a channel is specified: This overrides the header defined in the channel prototype.
|
||||
/// When no channel is specified: This flag requires --preview-command to be set.
|
||||
///
|
||||
/// The given value is parsed as a `MultiTemplate`. It is evaluated for every
|
||||
/// entry and its result is displayed above the preview panel.
|
||||
#[arg(
|
||||
long = "preview-header",
|
||||
value_name = "STRING",
|
||||
verbatim_doc_comment
|
||||
verbatim_doc_comment,
|
||||
conflicts_with = "no_preview"
|
||||
)]
|
||||
pub preview_header: Option<String>,
|
||||
|
||||
/// Preview footer template
|
||||
///
|
||||
/// When a channel is specified: This overrides the footer defined in the channel prototype.
|
||||
/// When no channel is specified: This flag requires --preview-command to be set.
|
||||
///
|
||||
/// The given value is parsed as a `MultiTemplate`. It is evaluated for every
|
||||
/// entry and its result is displayed below the preview panel.
|
||||
#[arg(
|
||||
long = "preview-footer",
|
||||
value_name = "STRING",
|
||||
verbatim_doc_comment
|
||||
verbatim_doc_comment,
|
||||
conflicts_with = "no_preview"
|
||||
)]
|
||||
pub preview_footer: Option<String>,
|
||||
|
||||
/// Source command to use for the current channel.
|
||||
///
|
||||
/// This overrides the command defined in the channel prototype.
|
||||
/// When a channel is specified: This overrides the command defined in the channel prototype.
|
||||
/// When no channel is specified: This creates an ad-hoc channel with the given command.
|
||||
///
|
||||
/// Example: `find . -name '*.rs'`
|
||||
#[arg(
|
||||
long = "source-command",
|
||||
@ -107,7 +159,9 @@ pub struct Cli {
|
||||
|
||||
/// Source display template to use for the current channel.
|
||||
///
|
||||
/// This overrides the display template defined in the channel prototype.
|
||||
/// When a channel is specified: This overrides the display template defined in the channel prototype.
|
||||
/// When no channel is specified: This flag requires --source-command to be set.
|
||||
///
|
||||
/// The template is used to format each entry in the results list.
|
||||
/// Example: `{split:/:-1}` (show only the last path segment)
|
||||
#[arg(
|
||||
@ -119,7 +173,9 @@ pub struct Cli {
|
||||
|
||||
/// Source output template to use for the current channel.
|
||||
///
|
||||
/// This overrides the output template defined in the channel prototype.
|
||||
/// When a channel is specified: This overrides the output template defined in the channel prototype.
|
||||
/// When no channel is specified: This flag requires --source-command to be set.
|
||||
///
|
||||
/// The template is used to format the final output when an entry is selected.
|
||||
/// Example: "{}" (output the full entry)
|
||||
#[arg(
|
||||
@ -131,7 +187,9 @@ pub struct Cli {
|
||||
|
||||
/// Preview command to use for the current channel.
|
||||
///
|
||||
/// This overrides the preview command defined in the channel prototype.
|
||||
/// When a channel is specified: This overrides the preview command defined in the channel prototype.
|
||||
/// When no channel is specified: This enables preview functionality for the ad-hoc channel.
|
||||
///
|
||||
/// Example: "cat {}" (where {} will be replaced with the entry)
|
||||
///
|
||||
/// Parts of the entry can be extracted positionally using the `delimiter`
|
||||
@ -142,19 +200,24 @@ pub struct Cli {
|
||||
short,
|
||||
long = "preview-command",
|
||||
value_name = "STRING",
|
||||
verbatim_doc_comment
|
||||
verbatim_doc_comment,
|
||||
conflicts_with = "no_preview"
|
||||
)]
|
||||
pub preview_command: Option<String>,
|
||||
|
||||
/// Layout orientation for the UI.
|
||||
///
|
||||
/// This overrides the layout/orientation defined in the channel prototype.
|
||||
/// When a channel is specified: Overrides the layout/orientation defined in the channel prototype.
|
||||
/// When no channel is specified: Sets the layout orientation for the ad-hoc channel.
|
||||
///
|
||||
/// Options are "landscape" or "portrait".
|
||||
#[arg(long = "layout", value_enum, verbatim_doc_comment)]
|
||||
pub layout: Option<LayoutOrientation>,
|
||||
|
||||
/// The working directory to start the application in.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This can be used to specify a different working directory for the
|
||||
/// application to start in. This is useful when the application is
|
||||
/// started from a different directory than the one the user wants to
|
||||
@ -164,14 +227,24 @@ pub struct Cli {
|
||||
|
||||
/// Try to guess the channel from the provided input prompt.
|
||||
///
|
||||
/// This flag automatically selects channel mode by guessing the appropriate channel.
|
||||
/// It conflicts with manually specifying a channel since it determines the channel automatically.
|
||||
///
|
||||
/// This can be used to automatically select a channel based on the input
|
||||
/// prompt by using the `shell_integration` mapping in the configuration
|
||||
/// file.
|
||||
#[arg(long, value_name = "STRING", verbatim_doc_comment)]
|
||||
#[arg(
|
||||
long,
|
||||
value_name = "STRING",
|
||||
verbatim_doc_comment,
|
||||
conflicts_with = "channel"
|
||||
)]
|
||||
pub autocomplete_prompt: Option<String>,
|
||||
|
||||
/// Use substring matching instead of fuzzy matching.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will use substring matching instead of fuzzy matching when
|
||||
/// searching for entries. This is useful when the user wants to search for
|
||||
/// an exact match instead of a fuzzy match e.g. to improve performance.
|
||||
@ -181,6 +254,8 @@ pub struct Cli {
|
||||
/// Automatically select and output the first entry if there is only one
|
||||
/// entry.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// Note that most channels stream entries asynchronously which means that
|
||||
/// knowing if there's only one entry will require waiting for the channel
|
||||
/// to finish loading first.
|
||||
@ -197,6 +272,8 @@ pub struct Cli {
|
||||
|
||||
/// Take the first entry from the list after the channel has finished loading.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will wait for the channel to finish loading all entries and then
|
||||
/// automatically select and output the first entry. Unlike `select_1`, this
|
||||
/// will always take the first entry regardless of how many entries are available.
|
||||
@ -210,6 +287,8 @@ pub struct Cli {
|
||||
|
||||
/// Take the first entry from the list as soon as it becomes available.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will immediately select and output the first entry as soon as it
|
||||
/// appears in the results, without waiting for the channel to finish loading.
|
||||
/// This is the fastest option when you just want the first result.
|
||||
@ -223,6 +302,8 @@ pub struct Cli {
|
||||
|
||||
/// Disable the remote control.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will disable the remote control panel and associated actions
|
||||
/// entirely. This is useful when the remote control is not needed or
|
||||
/// when the user wants `tv` to run in single-channel mode (e.g. when
|
||||
@ -233,6 +314,8 @@ pub struct Cli {
|
||||
|
||||
/// Disable the help panel.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will disable the help panel and associated toggling actions
|
||||
/// entirely. This is useful when the help panel is not needed or
|
||||
/// when the user wants `tv` to run with a minimal interface (e.g. when
|
||||
@ -243,28 +326,36 @@ pub struct Cli {
|
||||
|
||||
/// Change the display size in relation to the available area.
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
///
|
||||
/// This will crop the UI to a centered rectangle of the specified
|
||||
/// percentage of the available area (e.g. 0.5 for 50% x 50%).
|
||||
/// percentage of the available area.
|
||||
#[arg(
|
||||
long,
|
||||
value_name = "INTEGER",
|
||||
default_value = "100",
|
||||
verbatim_doc_comment
|
||||
verbatim_doc_comment,
|
||||
value_parser = clap::value_parser!(u16).range(10..=100)
|
||||
)]
|
||||
pub ui_scale: u16,
|
||||
|
||||
/// Percentage of the screen to allocate to the preview panel (1-99).
|
||||
///
|
||||
/// This value overrides any `preview_size` defined in configuration files or channel prototypes.
|
||||
#[arg(long, value_name = "INTEGER", verbatim_doc_comment)]
|
||||
/// When a channel is specified: This overrides any `preview_size` defined in configuration files or channel prototypes.
|
||||
/// When no channel is specified: This flag requires --preview-command to be set.
|
||||
#[arg(long, value_name = "INTEGER", verbatim_doc_comment, value_parser = clap::value_parser!(u16).range(1..=99), conflicts_with = "no_preview")]
|
||||
pub preview_size: Option<u16>,
|
||||
|
||||
/// Provide a custom configuration file to use.
|
||||
#[arg(long, value_name = "PATH", verbatim_doc_comment)]
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
#[arg(long, value_name = "PATH", verbatim_doc_comment, value_parser = validate_file_path)]
|
||||
pub config_file: Option<String>,
|
||||
|
||||
/// Provide a custom cable directory to use.
|
||||
#[arg(long, value_name = "PATH", verbatim_doc_comment)]
|
||||
///
|
||||
/// This flag works identically in both channel mode and ad-hoc mode.
|
||||
#[arg(long, value_name = "PATH", verbatim_doc_comment, value_parser = validate_directory_path)]
|
||||
pub cable_dir: Option<String>,
|
||||
|
||||
#[command(subcommand)]
|
||||
@ -302,3 +393,40 @@ pub enum LayoutOrientation {
|
||||
Landscape,
|
||||
Portrait,
|
||||
}
|
||||
|
||||
// Add validator functions
|
||||
fn validate_positive_float(s: &str) -> Result<f64, String> {
|
||||
match s.parse::<f64>() {
|
||||
Ok(val) if val > 0.0 => Ok(val),
|
||||
Ok(_) => Err("Value must be positive".to_string()),
|
||||
Err(_) => Err("Invalid number format".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_non_negative_float(s: &str) -> Result<f64, String> {
|
||||
match s.parse::<f64>() {
|
||||
Ok(val) if val >= 0.0 => Ok(val),
|
||||
Ok(_) => Err("Value must be non-negative".to_string()),
|
||||
Err(_) => Err("Invalid number format".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_file_path(s: &str) -> Result<String, String> {
|
||||
use std::path::Path;
|
||||
let path = Path::new(s);
|
||||
if path.exists() && path.is_file() {
|
||||
Ok(s.to_string())
|
||||
} else {
|
||||
Err(format!("File does not exist: {}", s))
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_directory_path(s: &str) -> Result<String, String> {
|
||||
use std::path::Path;
|
||||
let path = Path::new(s);
|
||||
if path.exists() && path.is_dir() {
|
||||
Ok(s.to_string())
|
||||
} else {
|
||||
Err(format!("Directory does not exist: {}", s))
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,27 @@ use crate::{
|
||||
|
||||
pub mod args;
|
||||
|
||||
/// # CLI Use Cases
|
||||
///
|
||||
/// The CLI interface supports two primary use cases:
|
||||
///
|
||||
/// ## 1. Channel-based mode (channel is specified)
|
||||
/// When a channel is provided, the CLI operates in **override mode**:
|
||||
/// - The channel provides the base configuration (source, preview, UI settings)
|
||||
/// - All CLI flags act as **overrides** to the channel's defaults
|
||||
/// - Most restrictions are enforced at the clap level using `conflicts_with`
|
||||
/// - Templates and keybindings are validated after clap parsing
|
||||
/// - More permissive - allows any combination of flags as they override channel defaults
|
||||
///
|
||||
/// ## 2. Ad-hoc mode (no channel specified)
|
||||
/// When no channel is provided, the CLI creates an **ad-hoc channel**:
|
||||
/// - Stricter validation rules apply for interdependent flags
|
||||
/// - `--preview-*` flags require `--preview-command` to be set
|
||||
/// - `--source-*` flags require `--source-command` to be set
|
||||
/// - This ensures the ad-hoc channel has all necessary components to function
|
||||
///
|
||||
/// The validation logic in `post_process()` enforces these constraints for ad-hoc mode
|
||||
/// while allowing full flexibility in channel-based mode.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PostProcessedCli {
|
||||
@ -26,7 +47,7 @@ pub struct PostProcessedCli {
|
||||
pub source_command_override: Option<Template>,
|
||||
pub source_display_override: Option<Template>,
|
||||
pub source_output_override: Option<Template>,
|
||||
pub working_directory: Option<String>,
|
||||
pub working_directory: Option<PathBuf>,
|
||||
pub autocomplete_prompt: Option<String>,
|
||||
|
||||
// Preview configuration
|
||||
@ -56,7 +77,6 @@ pub struct PostProcessedCli {
|
||||
|
||||
// Performance configuration
|
||||
pub tick_rate: Option<f64>,
|
||||
pub frame_rate: Option<f64>,
|
||||
pub watch_interval: Option<f64>,
|
||||
|
||||
// Configuration sources
|
||||
@ -105,7 +125,6 @@ impl Default for PostProcessedCli {
|
||||
|
||||
// Performance configuration
|
||||
tick_rate: None,
|
||||
frame_rate: None,
|
||||
watch_interval: None,
|
||||
|
||||
// Configuration sources
|
||||
@ -118,6 +137,20 @@ impl Default for PostProcessedCli {
|
||||
}
|
||||
}
|
||||
|
||||
/// Post-processes the raw CLI arguments into a structured format with validation.
|
||||
///
|
||||
/// This function handles the two main CLI use cases:
|
||||
///
|
||||
/// **Channel-based mode**: When `cli.channel` is provided, all flags are treated as
|
||||
/// overrides to the channel's configuration. Validation is minimal since the channel
|
||||
/// provides sensible defaults.
|
||||
///
|
||||
/// **Ad-hoc mode**: When no channel is specified, stricter validation ensures that
|
||||
/// interdependent flags are used correctly:
|
||||
/// - Preview flags (`--preview-offset`, `--preview-size`, etc.) require `--preview-command`
|
||||
/// - Source flags (`--source-display`, `--source-output`) require `--source-command`
|
||||
///
|
||||
/// This prevents creating broken ad-hoc channels that reference non-existent commands.
|
||||
pub fn post_process(cli: Cli) -> PostProcessedCli {
|
||||
// Parse literal keybindings passed through the CLI
|
||||
let keybindings = cli.keybindings.as_ref().map(|kb| {
|
||||
@ -144,13 +177,20 @@ pub fn post_process(cli: Cli) -> PostProcessedCli {
|
||||
})
|
||||
});
|
||||
|
||||
// Validate interdependent flags for ad-hoc mode (when no channel is specified)
|
||||
// This ensures ad-hoc channels have all necessary components to function properly
|
||||
validate_adhoc_mode_constraints(&cli);
|
||||
|
||||
// Determine channel and working_directory
|
||||
let (channel, working_directory) = match &cli.channel {
|
||||
Some(c) if Path::new(c).exists() => {
|
||||
// If the channel is a path, use it as the working directory
|
||||
(None, Some(c.clone()))
|
||||
(None, Some(PathBuf::from(c)))
|
||||
}
|
||||
_ => (cli.channel.clone(), cli.working_directory.clone()),
|
||||
_ => (
|
||||
cli.channel.clone(),
|
||||
cli.working_directory.as_ref().map(PathBuf::from),
|
||||
),
|
||||
};
|
||||
|
||||
// Parse source overrides if any source fields are provided
|
||||
@ -224,18 +264,71 @@ pub fn post_process(cli: Cli) -> PostProcessedCli {
|
||||
|
||||
// Performance configuration
|
||||
tick_rate: cli.tick_rate,
|
||||
frame_rate: cli.frame_rate,
|
||||
watch_interval: cli.watch,
|
||||
|
||||
// Configuration sources
|
||||
config_file: cli.config_file.map(expand_tilde),
|
||||
cable_dir: cli.cable_dir.map(expand_tilde),
|
||||
config_file: cli.config_file.map(|p| expand_tilde(&p)),
|
||||
cable_dir: cli.cable_dir.map(|p| expand_tilde(&p)),
|
||||
|
||||
// Command handling
|
||||
command: cli.command,
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates interdependent flags when operating in ad-hoc mode (no channel specified).
|
||||
///
|
||||
/// In ad-hoc mode, certain flags require their corresponding command to be specified:
|
||||
/// - Source-related flags (`--source-display`, `--source-output`) require `--source-command`
|
||||
/// - Preview-related flags (`--preview-offset`, `--preview-size`, etc.) require `--preview-command`
|
||||
///
|
||||
/// This validation ensures that ad-hoc channels have all necessary components to function.
|
||||
/// When a channel is specified, these validations are skipped as the channel provides defaults.
|
||||
fn validate_adhoc_mode_constraints(cli: &Cli) {
|
||||
// Skip validation if a channel is specified (channel-based mode)
|
||||
if cli.channel.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate source-related flags in ad-hoc mode
|
||||
if cli.source_command.is_none() {
|
||||
let source_flags = [
|
||||
("--source-display", cli.source_display.is_some()),
|
||||
("--source-output", cli.source_output.is_some()),
|
||||
("--preview-command", cli.preview_command.is_some()),
|
||||
];
|
||||
|
||||
for (flag_name, is_set) in source_flags {
|
||||
if is_set {
|
||||
cli_parsing_error_exit(&format!(
|
||||
"{} requires a source command when no channel is specified. \
|
||||
Either specify a channel (which may have its own source command) or provide --source-command.",
|
||||
flag_name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate preview-related flags in ad-hoc mode
|
||||
if cli.preview_command.is_none() {
|
||||
let preview_flags = [
|
||||
("--preview-offset", cli.preview_offset.is_some()),
|
||||
("--preview-size", cli.preview_size.is_some()),
|
||||
("--preview-header", cli.preview_header.is_some()),
|
||||
("--preview-footer", cli.preview_footer.is_some()),
|
||||
];
|
||||
|
||||
for (flag_name, is_set) in preview_flags {
|
||||
if is_set {
|
||||
cli_parsing_error_exit(&format!(
|
||||
"{} requires a preview command when no channel is specified. \
|
||||
Either specify a channel (which may have its own preview command) or provide --preview-command.",
|
||||
flag_name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cli_parsing_error_exit(message: &str) -> ! {
|
||||
eprintln!("Error parsing CLI arguments: {message}\n");
|
||||
std::process::exit(1);
|
||||
@ -369,7 +462,7 @@ pub fn version() -> String {
|
||||
|`-----------' |/
|
||||
~~~~~~~~~~~~~~~
|
||||
__ __ _ _
|
||||
/ /____ / /__ _ __(_)__ (_)__ ___
|
||||
/ /____ / /__ _ __(_)__ (_)__ ___
|
||||
/ __/ -_) / -_) |/ / (_-</ / _ \\/ _ \\
|
||||
\\__/\\__/_/\\__/|___/_/___/_/\\___/_//_/
|
||||
|
||||
@ -403,10 +496,9 @@ mod tests {
|
||||
"bat -n --color=always {}".to_string(),
|
||||
);
|
||||
assert_eq!(post_processed_cli.tick_rate, None);
|
||||
assert_eq!(post_processed_cli.frame_rate, None);
|
||||
assert_eq!(
|
||||
post_processed_cli.working_directory,
|
||||
Some("/home/user".to_string())
|
||||
Some(PathBuf::from("/home/user"))
|
||||
);
|
||||
}
|
||||
|
||||
@ -422,7 +514,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
post_processed_cli.working_directory,
|
||||
Some(".".to_string())
|
||||
Some(PathBuf::from("."))
|
||||
);
|
||||
assert_eq!(post_processed_cli.command, None);
|
||||
}
|
||||
|
@ -37,8 +37,6 @@ pub struct AppConfig {
|
||||
pub config_dir: PathBuf,
|
||||
#[serde(default = "default_cable_dir")]
|
||||
pub cable_dir: PathBuf,
|
||||
#[serde(default = "default_frame_rate")]
|
||||
pub frame_rate: f64,
|
||||
#[serde(default = "default_tick_rate")]
|
||||
pub tick_rate: f64,
|
||||
/// The default channel to use when no channel is specified
|
||||
@ -54,7 +52,6 @@ impl Hash for AppConfig {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.data_dir.hash(state);
|
||||
self.config_dir.hash(state);
|
||||
self.frame_rate.to_bits().hash(state);
|
||||
self.tick_rate.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
@ -314,10 +311,6 @@ fn project_directory() -> Option<ProjectDirs> {
|
||||
ProjectDirs::from("com", "", env!("CARGO_PKG_NAME"))
|
||||
}
|
||||
|
||||
fn default_frame_rate() -> f64 {
|
||||
60.0
|
||||
}
|
||||
|
||||
pub fn default_tick_rate() -> f64 {
|
||||
50.0
|
||||
}
|
||||
@ -393,8 +386,6 @@ mod tests {
|
||||
}
|
||||
|
||||
const USER_CONFIG_1: &str = r#"
|
||||
frame_rate = 30.0
|
||||
|
||||
[ui]
|
||||
ui_scale = 40
|
||||
theme = "television"
|
||||
@ -431,7 +422,6 @@ mod tests {
|
||||
|
||||
let mut default_config: Config =
|
||||
toml::from_str(DEFAULT_CONFIG).unwrap();
|
||||
default_config.application.frame_rate = 30.0;
|
||||
default_config.ui.ui_scale = 40;
|
||||
default_config.ui.theme = "television".to_string();
|
||||
default_config.keybindings.extend({
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::env;
|
||||
use std::io::{BufWriter, IsTerminal, Write, stdout};
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
|
||||
use anyhow::Result;
|
||||
@ -16,7 +16,7 @@ use television::{
|
||||
},
|
||||
utils::clipboard::CLIPBOARD,
|
||||
};
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use television::app::{App, AppOptions};
|
||||
use television::cli::{
|
||||
@ -66,7 +66,9 @@ async fn main() -> Result<()> {
|
||||
load_cable(&config.application.cable_dir).unwrap_or_else(|| exit(1));
|
||||
|
||||
// optionally change the working directory
|
||||
args.working_directory.as_ref().map(set_current_dir);
|
||||
if let Some(ref working_dir) = args.working_directory {
|
||||
set_current_dir(working_dir)?;
|
||||
}
|
||||
|
||||
// determine the channel to use based on the CLI arguments and configuration
|
||||
debug!("Determining channel...");
|
||||
@ -165,16 +167,7 @@ fn apply_cli_overrides(args: &PostProcessedCli, config: &mut Config) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_current_dir(path: &String) -> Result<()> {
|
||||
let path = Path::new(path);
|
||||
if !path.exists() {
|
||||
error!("Working directory \"{}\" does not exist", path.display());
|
||||
println!(
|
||||
"Error: Working directory \"{}\" does not exist",
|
||||
path.display()
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
pub fn set_current_dir(path: &PathBuf) -> Result<()> {
|
||||
env::set_current_dir(path)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -240,14 +233,14 @@ pub fn determine_channel(
|
||||
debug!("Creating ad-hoc channel with source command override");
|
||||
let source_cmd = args.source_command_override.as_ref().unwrap();
|
||||
|
||||
// Create an ad-hoc channel prototype with hidden UI elements
|
||||
// Create an ad-hoc channel prototype
|
||||
let mut prototype = ChannelPrototype::new("custom", source_cmd.raw());
|
||||
|
||||
// Set UI spec to hide preview and help, and set input header to "Custom Channel"
|
||||
// Set UI spec - only hide preview if no preview command is provided
|
||||
prototype.ui = Some(UiSpec {
|
||||
ui_scale: None,
|
||||
show_help_bar: Some(false),
|
||||
show_preview_panel: Some(false),
|
||||
show_preview_panel: Some(args.preview_command_override.is_some()),
|
||||
orientation: None,
|
||||
input_bar_position: None,
|
||||
preview_size: None,
|
||||
@ -307,12 +300,6 @@ pub fn determine_channel(
|
||||
if let Some(preview_offset) = &args.preview_offset_override {
|
||||
if let Some(ref mut preview) = channel_prototype.preview {
|
||||
preview.offset = Some(preview_offset.clone());
|
||||
} else {
|
||||
// Cannot set offset without a preview command
|
||||
eprintln!(
|
||||
"Error: Cannot set preview offset without a preview command"
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user