mirror of
https://github.com/TECHNOFAB11/tmux-copyrat.git
synced 2025-12-12 16:10:07 +01:00
135 lines
4.4 KiB
Rust
135 lines
4.4 KiB
Rust
use clap::Clap;
|
|
use std::collections::HashMap;
|
|
use std::str::FromStr;
|
|
|
|
use copyrat::{error, process, CliOpt};
|
|
|
|
mod tmux;
|
|
|
|
/// Main configuration, parsed from command line.
|
|
#[derive(Clap, Debug)]
|
|
#[clap(author, about, version)]
|
|
struct BridgeOpt {
|
|
/// Don't read options from Tmux.
|
|
///
|
|
/// By default, options formatted like `copyrat-*` are read from tmux.
|
|
/// However, you should consider reading them from the config file (the
|
|
/// default option) as this saves both a command call (about 10ms) and a
|
|
/// Regex compilation.
|
|
#[clap(long)]
|
|
ignore_options_from_tmux: bool,
|
|
|
|
/// Name of the copyrat temporary window.
|
|
///
|
|
/// Copyrat is launched in a temporary window of that name. The only pane
|
|
/// in this temp window gets swapped with the current active one for
|
|
/// in-place searching, then swapped back and killed after we exit.
|
|
#[clap(long, default_value = "[copyrat]")]
|
|
window_name: String,
|
|
|
|
/// Capture visible area or entire pane history.
|
|
#[clap(long, arg_enum, default_value = "visible-area")]
|
|
capture_region: tmux::CaptureRegion,
|
|
|
|
// Include CLI Options
|
|
#[clap(flatten)]
|
|
cli_options: CliOpt,
|
|
}
|
|
|
|
impl BridgeOpt {
|
|
/// Try parsing provided options, and update self with the valid values.
|
|
/// Unknown options are simply ignored.
|
|
pub fn merge_map(
|
|
&mut self,
|
|
options: &HashMap<String, String>,
|
|
) -> Result<(), error::ParseError> {
|
|
for (name, value) in options {
|
|
match name.as_ref() {
|
|
"@copyrat-capture" => {
|
|
self.capture_region = tmux::CaptureRegion::from_str(&value)?;
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
// Pass the call to cli_options.
|
|
self.cli_options.merge_map(options)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
///
|
|
fn main() -> Result<(), error::ParseError> {
|
|
let mut opt = BridgeOpt::parse();
|
|
|
|
if !opt.ignore_options_from_tmux {
|
|
let tmux_options: HashMap<String, String> = tmux::get_options("@copyrat-")?;
|
|
|
|
// Override default values with those coming from tmux.
|
|
opt.merge_map(&tmux_options)?;
|
|
}
|
|
|
|
// Identify active pane and capture its content.
|
|
let panes: Vec<tmux::Pane> = tmux::list_panes()?;
|
|
|
|
let active_pane = panes
|
|
.into_iter()
|
|
.find(|p| p.is_active)
|
|
.expect("Exactly one tmux pane should be active in the current window.");
|
|
|
|
let buffer = tmux::capture_pane(&active_pane, &opt.capture_region)?;
|
|
|
|
// We have to dance a little with Panes, because this process i/o streams
|
|
// are connected to the pane in the window newly created for us, instead
|
|
// of the active current pane.
|
|
let temp_pane_spec = format!("{}.0", opt.window_name);
|
|
tmux::swap_pane_with(&temp_pane_spec)?;
|
|
|
|
let selections = copyrat::run(buffer, &opt.cli_options);
|
|
|
|
tmux::swap_pane_with(&temp_pane_spec)?;
|
|
|
|
// Finally copy selection to a tmux buffer, and paste it to the active
|
|
// buffer if it was uppercased.
|
|
// TODO: consider getting rid of multi-selection mode.
|
|
|
|
// Execute a command on each group of selections (normal and uppercased).
|
|
let (normal_selections, uppercased_selections): (Vec<(String, bool)>, Vec<(String, bool)>) =
|
|
selections
|
|
.into_iter()
|
|
.partition(|(_text, uppercased)| !*uppercased);
|
|
|
|
let buffer_selections: String = normal_selections
|
|
.into_iter()
|
|
.map(|(text, _)| text)
|
|
.collect::<Vec<_>>()
|
|
.join("\n");
|
|
|
|
if buffer_selections.len() > 0 {
|
|
let args = vec!["set-buffer", &buffer_selections];
|
|
// Simply execute the command as is, and let the program crash on
|
|
// potential errors because it is not our responsibility.
|
|
process::execute("tmux", &args).unwrap();
|
|
}
|
|
|
|
let buffer_selections: String = uppercased_selections
|
|
.into_iter()
|
|
.map(|(text, _)| text)
|
|
.collect::<Vec<_>>()
|
|
.join("\n");
|
|
|
|
if buffer_selections.len() > 0 {
|
|
let args = vec!["set-buffer", &buffer_selections];
|
|
// Simply execute the command as is, and let the program crash on
|
|
// potential errors because it is not our responsibility.
|
|
process::execute("tmux", &args).unwrap();
|
|
|
|
let args = vec!["paste-buffer", "-t", active_pane.id.as_str()];
|
|
// Simply execute the command as is, and let the program crash on
|
|
// potential errors because it is not our responsibility.
|
|
process::execute("tmux", &args).unwrap();
|
|
}
|
|
|
|
Ok(())
|
|
}
|