Refactor clipboard to make it easier to feature gate std::process

This commit is contained in:
Blaž Hrastnik 2022-03-27 17:20:23 +09:00
parent 4940db3e2d
commit 8611c5b84e
No known key found for this signature in database
GPG Key ID: 1238B9C4AD889640

View File

@ -16,12 +16,12 @@ pub trait ClipboardProvider: std::fmt::Debug {
macro_rules! command_provider { macro_rules! command_provider {
(paste => $get_prg:literal $( , $get_arg:literal )* ; copy => $set_prg:literal $( , $set_arg:literal )* ; ) => {{ (paste => $get_prg:literal $( , $get_arg:literal )* ; copy => $set_prg:literal $( , $set_arg:literal )* ; ) => {{
Box::new(provider::CommandProvider { Box::new(provider::command::Provider {
get_cmd: provider::CommandConfig { get_cmd: provider::command::Config {
prg: $get_prg, prg: $get_prg,
args: &[ $( $get_arg ),* ], args: &[ $( $get_arg ),* ],
}, },
set_cmd: provider::CommandConfig { set_cmd: provider::command::Config {
prg: $set_prg, prg: $set_prg,
args: &[ $( $set_arg ),* ], args: &[ $( $set_arg ),* ],
}, },
@ -35,20 +35,20 @@ macro_rules! command_provider {
primary_paste => $pr_get_prg:literal $( , $pr_get_arg:literal )* ; primary_paste => $pr_get_prg:literal $( , $pr_get_arg:literal )* ;
primary_copy => $pr_set_prg:literal $( , $pr_set_arg:literal )* ; primary_copy => $pr_set_prg:literal $( , $pr_set_arg:literal )* ;
) => {{ ) => {{
Box::new(provider::CommandProvider { Box::new(provider::command::Provider {
get_cmd: provider::CommandConfig { get_cmd: provider::command::Config {
prg: $get_prg, prg: $get_prg,
args: &[ $( $get_arg ),* ], args: &[ $( $get_arg ),* ],
}, },
set_cmd: provider::CommandConfig { set_cmd: provider::command::Config {
prg: $set_prg, prg: $set_prg,
args: &[ $( $set_arg ),* ], args: &[ $( $set_arg ),* ],
}, },
get_primary_cmd: Some(provider::CommandConfig { get_primary_cmd: Some(provider::command::Config {
prg: $pr_get_prg, prg: $pr_get_prg,
args: &[ $( $pr_get_arg ),* ], args: &[ $( $pr_get_arg ),* ],
}), }),
set_primary_cmd: Some(provider::CommandConfig { set_primary_cmd: Some(provider::command::Config {
prg: $pr_set_prg, prg: $pr_set_prg,
args: &[ $( $pr_set_arg ),* ], args: &[ $( $pr_set_arg ),* ],
}), }),
@ -63,6 +63,8 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> { pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
use command::exists;
if exists("pbcopy") && exists("pbpaste") { if exists("pbcopy") && exists("pbpaste") {
command_provider! { command_provider! {
paste => "pbpaste"; paste => "pbpaste";
@ -75,6 +77,7 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
#[cfg(not(any(windows, target_os = "macos")))] #[cfg(not(any(windows, target_os = "macos")))]
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> { pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
use provider::command::{env_var_is_set, exists, is_exit_success};
// TODO: support for user-defined provider, probably when we have plugin support by setting a // TODO: support for user-defined provider, probably when we have plugin support by setting a
// variable? // variable?
@ -116,26 +119,9 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
} }
} }
fn exists(executable_name: &str) -> bool {
which::which(executable_name).is_ok()
}
fn env_var_is_set(env_var_name: &str) -> bool {
std::env::var_os(env_var_name).is_some()
}
fn is_exit_success(program: &str, args: &[&str]) -> bool {
std::process::Command::new(program)
.args(args)
.output()
.ok()
.and_then(|out| out.status.success().then(|| ())) // TODO: use then_some when stabilized
.is_some()
}
mod provider { mod provider {
use super::{ClipboardProvider, ClipboardType}; use super::{ClipboardProvider, ClipboardType};
use anyhow::{bail, Context as _, Result}; use anyhow::Result;
use std::borrow::Cow; use std::borrow::Cow;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -210,13 +196,34 @@ fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> R
} }
} }
pub mod command {
use super::*;
use anyhow::{bail, Context as _, Result};
pub fn exists(executable_name: &str) -> bool {
which::which(executable_name).is_ok()
}
pub fn env_var_is_set(env_var_name: &str) -> bool {
std::env::var_os(env_var_name).is_some()
}
pub fn is_exit_success(program: &str, args: &[&str]) -> bool {
std::process::Command::new(program)
.args(args)
.output()
.ok()
.and_then(|out| out.status.success().then(|| ())) // TODO: use then_some when stabilized
.is_some()
}
#[derive(Debug)] #[derive(Debug)]
pub struct CommandConfig { pub struct Config {
pub prg: &'static str, pub prg: &'static str,
pub args: &'static [&'static str], pub args: &'static [&'static str],
} }
impl CommandConfig { impl Config {
fn execute(&self, input: Option<&str>, pipe_output: bool) -> Result<Option<String>> { fn execute(&self, input: Option<&str>, pipe_output: bool) -> Result<Option<String>> {
use std::io::Write; use std::io::Write;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
@ -254,14 +261,14 @@ fn execute(&self, input: Option<&str>, pipe_output: bool) -> Result<Option<Strin
} }
#[derive(Debug)] #[derive(Debug)]
pub struct CommandProvider { pub struct Provider {
pub get_cmd: CommandConfig, pub get_cmd: Config,
pub set_cmd: CommandConfig, pub set_cmd: Config,
pub get_primary_cmd: Option<CommandConfig>, pub get_primary_cmd: Option<Config>,
pub set_primary_cmd: Option<CommandConfig>, pub set_primary_cmd: Option<Config>,
} }
impl ClipboardProvider for CommandProvider { impl ClipboardProvider for Provider {
fn name(&self) -> Cow<str> { fn name(&self) -> Cow<str> {
if self.get_cmd.prg != self.set_cmd.prg { if self.get_cmd.prg != self.set_cmd.prg {
Cow::Owned(format!("{}+{}", self.get_cmd.prg, self.set_cmd.prg)) Cow::Owned(format!("{}+{}", self.get_cmd.prg, self.set_cmd.prg))
@ -301,3 +308,4 @@ fn set_contents(&mut self, value: String, clipboard_type: ClipboardType) -> Resu
} }
} }
} }
}