mirror of
https://github.com/alexpasmantier/television.git
synced 2025-07-17 07:30:00 +00:00

Before: ```toml [shell_integration.commands] # Add your commands here. Each key is a command that will trigger tv with the # corresponding channel as value. # Example: say you want the following prompts to trigger the following channels # when pressing <CTRL-T>: # `git checkout` should trigger the `git-branches` channel # `ls` should trigger the `dirs` channel # `cat` should trigger the `files` channel # # You would add the following to your configuration file: # ``` # [shell_integration.commands] # "git checkout" = "git-branch" # "ls" = "dirs" # "cat" = "files" # ``` # environment variables "export" = "env" "unset" = "env" # dirs channel "cd" = "dirs" "ls" = "dirs" "rmdir" = "dirs" # files channel "cat" = "files" "less" = "files" "head" = "files" "tail" = "files" "vim" = "files" "bat" = "files" # git-diff channel "git add" = "git-diff" # git-branch channel "git checkout" = "git-branch" "git branch -d" = "git-branch" # docker-images channel "docker run" = "docker-images" # gitrepos channel "nvim" = "git-repos" ``` After ```toml [shell_integration.channel_triggers] # Add your channel triggers here. Each key is a channel that will be triggered # by the corresponding commands. # Example: say you want the following commands to trigger the following channels # when pressing <CTRL-T>: # `git checkout` should trigger the `git-branches` channel # `ls` should trigger the `dirs` channel # `cat` and `cp` should trigger the `files` channel # # You would add the following to your configuration file: # ``` # [shell_integration.channel_triggers] # "git-branches" = ["git checkout"] # "dirs" = ["ls"] # "files" = ["cat", "cp"] # ``` "env" = ["export", "unset"] "dirs" = ["cd", "ls", "rmdir"] "files" = ["cat", "less", "head", "tail", "vim", "bat"] "git-diff" = ["git add"] "git-branch" = ["git checkout", "git branch -d"] "docker-images" = ["docker run"] "git-repos" = ["nvim"] ```
137 lines
4.4 KiB
Rust
137 lines
4.4 KiB
Rust
use std::env;
|
|
use std::io::{stdout, BufWriter, IsTerminal, Write};
|
|
use std::path::Path;
|
|
use std::process::exit;
|
|
|
|
use anyhow::Result;
|
|
use clap::Parser;
|
|
use tracing::{debug, error, info};
|
|
|
|
use television::app::App;
|
|
use television::channels::{
|
|
entry::PreviewType, stdin::Channel as StdinChannel, TelevisionChannel,
|
|
};
|
|
use television::cli::{
|
|
guess_channel_from_prompt, list_channels, Cli, ParsedCliChannel,
|
|
PostProcessedCli,
|
|
};
|
|
|
|
use television::config::{Config, ConfigEnv};
|
|
use television::utils::shell::render_autocomplete_script_template;
|
|
use television::utils::{
|
|
shell::{completion_script, Shell},
|
|
stdin::is_readable_stdin,
|
|
};
|
|
|
|
#[tokio::main(flavor = "multi_thread")]
|
|
async fn main() -> Result<()> {
|
|
television::errors::init()?;
|
|
television::logging::init()?;
|
|
|
|
let args: PostProcessedCli = Cli::parse().into();
|
|
debug!("{:?}", args);
|
|
|
|
let mut config = Config::new(&ConfigEnv::init()?)?;
|
|
|
|
if let Some(command) = args.command {
|
|
match command {
|
|
television::cli::Command::ListChannels => {
|
|
list_channels();
|
|
exit(0);
|
|
}
|
|
television::cli::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
|
|
// shell autocomplete and command history in tv
|
|
let script = render_autocomplete_script_template(
|
|
target_shell,
|
|
completion_script(target_shell)?,
|
|
&config.shell_integration,
|
|
)?;
|
|
println!("{script}");
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
config.config.tick_rate =
|
|
args.tick_rate.unwrap_or(config.config.tick_rate);
|
|
if args.no_preview {
|
|
config.ui.show_preview_panel = false;
|
|
}
|
|
|
|
if let Some(working_directory) = args.working_directory {
|
|
let path = Path::new(&working_directory);
|
|
if !path.exists() {
|
|
error!(
|
|
"Working directory \"{}\" does not exist",
|
|
&working_directory
|
|
);
|
|
println!(
|
|
"Error: Working directory \"{}\" does not exist",
|
|
&working_directory
|
|
);
|
|
exit(1);
|
|
}
|
|
env::set_current_dir(path)?;
|
|
}
|
|
|
|
match App::new(
|
|
{
|
|
if is_readable_stdin() {
|
|
debug!("Using stdin channel");
|
|
TelevisionChannel::Stdin(StdinChannel::new(
|
|
args.preview_command.map(PreviewType::Command),
|
|
))
|
|
} else if let Some(prompt) = args.autocomplete_prompt {
|
|
let channel = guess_channel_from_prompt(
|
|
&prompt,
|
|
&config.shell_integration.commands,
|
|
)?;
|
|
debug!("Using guessed channel: {:?}", channel);
|
|
match channel {
|
|
ParsedCliChannel::Builtin(c) => c.to_channel(),
|
|
ParsedCliChannel::Cable(c) => {
|
|
TelevisionChannel::Cable(c.into())
|
|
}
|
|
}
|
|
} else {
|
|
debug!("Using {:?} channel", args.channel);
|
|
match args.channel {
|
|
ParsedCliChannel::Builtin(c) => c.to_channel(),
|
|
ParsedCliChannel::Cable(c) => {
|
|
TelevisionChannel::Cable(c.into())
|
|
}
|
|
}
|
|
}
|
|
},
|
|
config,
|
|
&args.passthrough_keybindings,
|
|
args.input,
|
|
) {
|
|
Ok(mut app) => {
|
|
stdout().flush()?;
|
|
let output = app.run(stdout().is_terminal()).await?;
|
|
info!("{:?}", output);
|
|
// lock stdout
|
|
let stdout_handle = stdout().lock();
|
|
let mut bufwriter = BufWriter::new(stdout_handle);
|
|
if let Some(passthrough) = output.passthrough {
|
|
writeln!(bufwriter, "{passthrough}")?;
|
|
}
|
|
if let Some(entries) = output.selected_entries {
|
|
for entry in &entries {
|
|
writeln!(bufwriter, "{}", entry.stdout_repr())?;
|
|
}
|
|
}
|
|
bufwriter.flush()?;
|
|
exit(0);
|
|
}
|
|
Err(err) => {
|
|
println!("{err:?}");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|