docs(man): add man pages for tv (#397)

![image](https://github.com/user-attachments/assets/8e8fc26e-2a55-4a2e-8b55-fb92cace1a02)
This commit is contained in:
Alexandre Pasmantier 2025-03-18 01:23:02 +01:00 committed by GitHub
parent 88a4f04680
commit 0edf224502
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 302 additions and 145 deletions

View File

@ -53,7 +53,6 @@ jobs:
target: x86_64-apple-darwin
architecture: x86_64
binary-postfix: ""
binary-name: tv
use-cross: false
- os: macos-latest
os-name: macos
@ -61,35 +60,30 @@ jobs:
architecture: arm64
binary-postfix: ""
use-cross: false
binary-name: tv
- os: ubuntu-latest
os-name: linux
target: x86_64-unknown-linux-gnu
architecture: x86_64
binary-postfix: ""
use-cross: false
binary-name: tv
- os: windows-latest
os-name: windows
target: x86_64-pc-windows-msvc
architecture: x86_64
binary-postfix: ".exe"
use-cross: false
binary-name: tv
- os: ubuntu-latest
os-name: linux
target: aarch64-unknown-linux-gnu
architecture: arm64
binary-postfix: ""
use-cross: true
binary-name: tv
- os: ubuntu-latest
os-name: linux
target: i686-unknown-linux-gnu
architecture: i686
binary-postfix: ""
use-cross: true
binary-name: tv
steps:
- name: Checkout repository
@ -129,27 +123,30 @@ jobs:
shell: bash
run: |
cd target/${{ matrix.target }}/release
####### reduce binary size by removing debug symbols #######
BINARY_NAME=${{ matrix.binary-name }}${{ matrix.binary-postfix }}
echo "BINARY_NAME=$BINARY_NAME" >> "$GITHUB_ENV"
BIN=target/${{ matrix.target }}/release/tv${{ matrix.binary-postfix }}
echo "BIN=$BIN" >> "$GITHUB_ENV"
if [[ ${{ matrix.target }} == aarch64-unknown-linux-gnu ]]; then
GCC_PREFIX="aarch64-linux-gnu-"
else
GCC_PREFIX=""
fi
"$GCC_PREFIX"strip $BINARY_NAME
"$GCC_PREFIX"strip $BIN
########## create tar.gz ##########
RELEASE_NAME=${{ matrix.binary-name }}-${GITHUB_REF/refs\/tags\//}-${{ matrix.os-name }}-${{ matrix.architecture }}
RELEASE_NAME=tv-${GITHUB_REF/refs\/tags\//}-${{ matrix.os-name }}-${{ matrix.architecture }}
echo "RELEASE_NAME=$RELEASE_NAME" >> "$GITHUB_ENV"
tar czvf $RELEASE_NAME.tar.gz $BINARY_NAME
# create the directory for the archive
mkdir -p "$RELEASE_NAME"/doc
cp $BIN "$RELEASE_NAME"/
cp {README.md,LICENSE} "$RELEASE_NAME"/
cp {CHANGELOG.md,docs/*,man/*} "$RELEASE_NAME"/doc/
tar czvf "$RELEASE_NAME".tar.gz "$RELEASE_NAME"
########## create sha256 ##########
@ -161,9 +158,8 @@ jobs:
fi
- name: Packaging with zip format
if: runner.os == 'Windows'
working-directory: 'target/${{ matrix.target }}/release'
run: |
Compress-Archive -Path "$env:BINARY_NAME" -Destination "$($env:RELEASE_NAME).zip"
Compress-Archive -Path "$env:BIN" -Destination "$($env:RELEASE_NAME).zip"
(Get-FileHash "$($env:RELEASE_NAME).zip" -Algorithm SHA256).Hash.ToLower() > "$($env:RELEASE_NAME).zip.sha256"
- name: Releasing assets
@ -171,9 +167,9 @@ jobs:
with:
files: |
target/${{ matrix.target }}/release/${{ matrix.binary-name }}-*.tar.gz
target/${{ matrix.target }}/release/${{ matrix.binary-name }}-*.zip
target/${{ matrix.target }}/release/${{ matrix.binary-name }}-*.sha256
tv-*.tar.gz
tv-*.zip
tv-*.sha256
env:
@ -235,6 +231,11 @@ jobs:
mkdir -p "$dir"
echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV
- name: Copy man page
shell: bash
run: |
cp man/tv.1 "$DEPLOY_DIR/"
- name: Build release binary
shell: bash
run: |

17
Cargo.lock generated
View File

@ -426,6 +426,16 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "clap_mangen"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "724842fa9b144f9b89b3f3d371a89f3455eea660361d13a554f68f8ae5d6c13a"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "clipboard-win"
version = "5.4.0"
@ -1839,6 +1849,12 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -2168,6 +2184,7 @@ dependencies = [
"bat",
"better-panic",
"clap",
"clap_mangen",
"clipboard-win",
"criterion",
"crossterm",

View File

@ -23,6 +23,7 @@ include = [
"cable",
]
rust-version = "1.83"
build = "build.rs"
[lib]
path = "television/lib.rs"
@ -74,6 +75,12 @@ simd = ["dep:simdutf8"]
zero-copy = []
default = ["zero-copy", "simd"]
[build-dependencies]
clap = { version = "4.5", features = ["derive", "cargo"] }
clap_mangen = "0.2.26"
[[bin]]
bench = false
path = "television/main.rs"

28
build.rs Normal file
View File

@ -0,0 +1,28 @@
use clap::CommandFactory;
use std::path::PathBuf;
include!("television/cli/args.rs");
/// generate the man page from the Clap configuration
fn build_man_page() -> std::io::Result<()> {
let out_dir = PathBuf::from(
std::env::var_os("OUT_DIR").ok_or(std::io::ErrorKind::NotFound)?,
);
std::fs::create_dir_all(&out_dir)?;
let cmd = Cli::command();
let man = clap_mangen::Man::new(cmd);
let mut buffer = Vec::<u8>::default();
man.render(&mut buffer)?;
let out_path = out_dir.join("tv.1");
std::fs::write(&out_path, &buffer)?;
eprintln!("Wrote man page to {out_path:?}");
std::fs::write(PathBuf::from("./man").join("tv.1"), &buffer)?;
eprintln!("Wrote man page to ./man directory.");
Ok(())
}
fn main() {
println!("cargo::rerun-if-changed=television/cli/args.rs");
build_man_page().expect("Failed to generate man page.");
}

100
man/tv.1 Normal file
View File

@ -0,0 +1,100 @@
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.TH television 1 "television 0.10.9"
.SH NAME
television \- A cross\-platform, fast and extensible general purpose fuzzy finder TUI.
.SH SYNOPSIS
\fBtelevision\fR [\fB\-p\fR|\fB\-\-preview\fR] [\fB\-\-no\-preview\fR] [\fB\-\-delimiter\fR] [\fB\-t\fR|\fB\-\-tick\-rate\fR] [\fB\-f\fR|\fB\-\-frame\-rate\fR] [\fB\-\-passthrough\-keybindings\fR] [\fB\-i\fR|\fB\-\-input\fR] [\fB\-\-autocomplete\-prompt\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
.TP
\fB\-p\fR, \fB\-\-preview\fR=\fISTRING\fR
A preview command to use with the stdin channel.
If provided, the preview command will be executed and formatted using
the entry.
Example: "bat \-n \-\-color=always {}" (where {} will be replaced with
the entry)
Parts of the entry can be extracted positionally using the `delimiter`
option.
Example: "echo {0} {1}" will split the entry by the delimiter and pass
the first two fields to the command.
.TP
\fB\-\-no\-preview\fR
Disable the preview panel entirely on startup.
.TP
\fB\-\-delimiter\fR=\fISTRING\fR [default: ]
The delimiter used to extract fields from the entry to provide to the
preview command.
See the `preview` option for more information.
.TP
\fB\-t\fR, \fB\-\-tick\-rate\fR=\fIFLOAT\fR
The application\*(Aqs tick rate.
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.
This option is deprecated and will be removed in a future release.
.TP
\fB\-\-passthrough\-keybindings\fR=\fISTRING\fR
Passthrough keybindings (comma separated, e.g. "q,ctrl\-w,ctrl\-t")
These keybindings will trigger selection of the current entry and be
passed through to stdout along with the entry to be handled by the
parent process.
.TP
\fB\-i\fR, \fB\-\-input\fR=\fISTRING\fR
Input text to pass to the channel to prefill the prompt.
This can be used to provide a default value for the prompt upon
startup.
.TP
\fB\-\-autocomplete\-prompt\fR=\fISTRING\fR
Try to guess the channel from the provided input prompt.
This can be used to automatically select a channel based on the input
prompt by using the `shell_integration` mapping in the configuration
file.
.TP
\fB\-h\fR, \fB\-\-help\fR
Print help (see a summary with \*(Aq\-h\*(Aq)
.TP
\fB\-V\fR, \fB\-\-version\fR
Print version
.TP
[\fICHANNEL\fR] [default: files]
Which channel shall we watch?
A list of the available channels can be displayed using the
`list\-channels` command. The channel can also be changed from within
the application.
.TP
[\fIPATH\fR]
The working directory to start the application in.
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
interact with.
.SH SUBCOMMANDS
.TP
television\-list\-channels(1)
Lists the available channels
.TP
television\-init(1)
Initializes shell completion ("tv init zsh")
.TP
television\-help(1)
Print this message or the help of the given subcommand(s)
.SH VERSION
v0.10.9
.SH AUTHORS
Alexandre Pasmantier <alex.pasmant@gmail.com>

124
television/cli/args.rs Normal file
View File

@ -0,0 +1,124 @@
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// Which channel shall we watch?
///
/// 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,
default_value = "files",
index = 1,
verbatim_doc_comment
)]
pub channel: String,
/// A preview command to use with the stdin channel.
///
/// If provided, the preview command will be executed and formatted using
/// the entry.
/// Example: "bat -n --color=always {}" (where {} will be replaced with
/// the entry)
///
/// Parts of the entry can be extracted positionally using the `delimiter`
/// option.
/// Example: "echo {0} {1}" will split the entry by the delimiter and pass
/// the first two fields to the command.
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
pub preview: Option<String>,
/// Disable the preview panel entirely on startup.
#[arg(long, default_value = "false", verbatim_doc_comment)]
pub no_preview: bool,
/// The delimiter used to extract fields from the entry to provide to the
/// preview command.
///
/// See the `preview` option for more information.
#[arg(long, value_name = "STRING", default_value = " ", value_parser = delimiter_parser, verbatim_doc_comment)]
pub delimiter: String,
/// The application's tick rate.
///
/// 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)]
pub tick_rate: 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>,
/// Passthrough keybindings (comma separated, e.g. "q,ctrl-w,ctrl-t")
///
/// These keybindings will trigger selection of the current entry and be
/// passed through to stdout along with the entry to be handled by the
/// parent process.
#[arg(long, value_name = "STRING", verbatim_doc_comment)]
pub passthrough_keybindings: Option<String>,
/// Input text to pass to the channel to prefill the prompt.
///
/// This can be used to provide a default value for the prompt upon
/// startup.
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
pub input: Option<String>,
/// The working directory to start the application in.
///
/// 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
/// interact with.
#[arg(value_name = "PATH", index = 2, verbatim_doc_comment)]
pub working_directory: Option<String>,
/// Try to guess the channel from the provided input prompt.
///
/// 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)]
pub autocomplete_prompt: Option<String>,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Subcommand, Debug, PartialEq, Clone)]
pub enum Command {
/// Lists the available channels.
ListChannels,
/// Initializes shell completion ("tv init zsh")
#[clap(name = "init")]
InitShell {
/// The shell for which to generate the autocompletion script
#[arg(value_enum)]
shell: Shell,
},
}
#[derive(Debug, Clone, Copy, PartialEq, ValueEnum)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
Cmd,
}
#[allow(clippy::unnecessary_wraps)]
fn delimiter_parser(s: &str) -> Result<String, String> {
Ok(match s {
"" => " ".to_string(),
"\\t" => "\t".to_string(),
_ => s.to_string(),
})
}

View File

@ -2,131 +2,19 @@ use rustc_hash::FxHashMap;
use std::path::Path;
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand, ValueEnum};
use tracing::debug;
use crate::channels::{
cable::CableChannelPrototype, entry::PreviewCommand, CliTvChannel,
};
use crate::cli::args::{Cli, Command, Shell};
use crate::utils::shell::Shell as UtilShell;
use crate::{
cable,
config::{get_config_dir, get_data_dir},
};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Cli {
/// Which channel shall we watch?
///
/// 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,
default_value = "files",
index = 1,
verbatim_doc_comment
)]
pub channel: String,
/// A preview command to use with the stdin channel.
///
/// If provided, the preview command will be executed and formatted using
/// the entry.
/// Example: "bat -n --color=always {}" (where {} will be replaced with
/// the entry)
///
/// Parts of the entry can be extracted positionally using the `delimiter`
/// option.
/// Example: "echo {0} {1}" will split the entry by the delimiter and pass
/// the first two fields to the command.
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
pub preview: Option<String>,
/// Disable the preview panel entirely on startup.
#[arg(long, default_value = "false", verbatim_doc_comment)]
pub no_preview: bool,
/// The delimiter used to extract fields from the entry to provide to the
/// preview command.
///
/// See the `preview` option for more information.
#[arg(long, value_name = "STRING", default_value = " ", value_parser = delimiter_parser, verbatim_doc_comment)]
pub delimiter: String,
/// The application's tick rate.
///
/// 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)]
pub tick_rate: 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>,
/// Passthrough keybindings (comma separated, e.g. "q,ctrl-w,ctrl-t")
///
/// These keybindings will trigger selection of the current entry and be
/// passed through to stdout along with the entry to be handled by the
/// parent process.
#[arg(long, value_name = "STRING", verbatim_doc_comment)]
pub passthrough_keybindings: Option<String>,
/// Input text to pass to the channel to prefill the prompt.
///
/// This can be used to provide a default value for the prompt upon
/// startup.
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
pub input: Option<String>,
/// The working directory to start the application in.
///
/// 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
/// interact with.
#[arg(value_name = "PATH", index = 2, verbatim_doc_comment)]
pub working_directory: Option<String>,
/// Try to guess the channel from the provided input prompt.
///
/// 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)]
pub autocomplete_prompt: Option<String>,
#[command(subcommand)]
command: Option<Command>,
}
#[derive(Subcommand, Debug, PartialEq, Clone)]
pub enum Command {
/// Lists the available channels.
ListChannels,
/// Initializes shell completion ("tv init zsh")
#[clap(name = "init")]
InitShell {
/// The shell for which to generate the autocompletion script
#[arg(value_enum)]
shell: Shell,
},
}
#[derive(Debug, Clone, Copy, PartialEq, ValueEnum)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
Cmd,
}
pub mod args;
impl From<Shell> for UtilShell {
fn from(val: Shell) -> Self {
@ -342,15 +230,6 @@ pub fn guess_channel_from_prompt(
Err(anyhow!("No channel found for prompt: {}", prompt))
}
#[allow(clippy::unnecessary_wraps)]
fn delimiter_parser(s: &str) -> Result<String, String> {
Ok(match s {
"" => " ".to_string(),
"\\t" => "\t".to_string(),
_ => s.to_string(),
})
}
const VERSION_MESSAGE: &str = env!("CARGO_PKG_VERSION");
pub fn version() -> String {

View File

@ -13,7 +13,8 @@ use television::channels::{
entry::PreviewType, stdin::Channel as StdinChannel, TelevisionChannel,
};
use television::cli::{
guess_channel_from_prompt, list_channels, Cli, ParsedCliChannel,
args::{Cli, Command},
guess_channel_from_prompt, list_channels, ParsedCliChannel,
PostProcessedCli,
};
@ -36,11 +37,11 @@ async fn main() -> Result<()> {
if let Some(command) = args.command {
match command {
television::cli::Command::ListChannels => {
Command::ListChannels => {
list_channels();
exit(0);
}
television::cli::Command::InitShell { shell } => {
Command::InitShell { shell } => {
let target_shell = Shell::from(shell);
// the completion scripts for the various shells are templated
// so that it's possible to override the keybindings triggering