Use command for clipboard instead of copypasta (#36)

* use copy command instead of copypasta

* remove a step for installing dependencies

* rename copy_string to copy_to_clipboard
This commit is contained in:
Takayuki Maeda 2021-08-08 23:25:22 +09:00 committed by GitHub
parent 5da6b1b796
commit d493f46875
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 95 deletions

View File

@ -83,10 +83,5 @@ jobs:
with: with:
path: target path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- name: Install dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get install libxcb-xkb-dev
sudo apt install libxcb-composite0-dev
- name: Run Tests - name: Run Tests
run: cargo test --workspace -- --skip=e2e --color always run: cargo test --workspace -- --skip=e2e --color always

32
Cargo.lock generated
View File

@ -220,7 +220,6 @@ dependencies = [
"objc", "objc",
"objc-foundation", "objc-foundation",
"objc_id", "objc_id",
"x11-clipboard",
] ]
[[package]] [[package]]
@ -556,6 +555,7 @@ dependencies = [
"toml", "toml",
"tui", "tui",
"unicode-width", "unicode-width",
"which",
] ]
[[package]] [[package]]
@ -1869,6 +1869,17 @@ dependencies = [
"webpki", "webpki",
] ]
[[package]]
name = "which"
version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
dependencies = [
"either",
"lazy_static",
"libc",
]
[[package]] [[package]]
name = "whoami" name = "whoami"
version = "1.1.2" version = "1.1.2"
@ -1929,25 +1940,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "x11-clipboard"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b397ace6e980510de59a4fe3d4c758dffab231d6d747ce9fa1aba6b6035d5f32"
dependencies = [
"xcb",
]
[[package]]
name = "xcb"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
dependencies = [
"libc",
"log",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.3.0" version = "1.3.0"

View File

@ -36,8 +36,5 @@ async-trait = "0.1.50"
itertools = "0.10.0" itertools = "0.10.0"
rust_decimal = "1.15" rust_decimal = "1.15"
[target.'cfg(any(target_os = "macos", windows))'.dependencies] [target.'cfg(all(target_family="unix",not(target_os="macos")))'.dependencies]
copypasta = { version = "0.7.0", default-features = false } which = "4.1"
[target.'cfg(not(any(target_os = "macos", windows)))'.dependencies]
copypasta = { version = "0.7.0", features = ["x11"], default-features = false }

View File

@ -31,7 +31,7 @@ impl DatabaseTreeItems {
item.set_collapsed(false); item.set_collapsed(false);
item item
} else { } else {
let mut item = item.clone(); let mut item = item;
item.show(); item.show();
item item
} }

View File

@ -1,4 +1,4 @@
use crate::clipboard::Clipboard; use crate::clipboard::copy_to_clipboard;
use crate::components::{CommandInfo, Component as _, DrawableComponent as _, EventState}; use crate::components::{CommandInfo, Component as _, DrawableComponent as _, EventState};
use crate::database::{MySqlPool, Pool, PostgresPool, RECORDS_LIMIT_PER_PAGE}; use crate::database::{MySqlPool, Pool, PostgresPool, RECORDS_LIMIT_PER_PAGE};
use crate::event::Key; use crate::event::Key;
@ -31,7 +31,6 @@ pub struct App {
databases: DatabasesComponent, databases: DatabasesComponent,
connections: ConnectionsComponent, connections: ConnectionsComponent,
table_status: TableStatusComponent, table_status: TableStatusComponent,
clipboard: Clipboard,
pool: Option<Box<dyn Pool>>, pool: Option<Box<dyn Pool>>,
pub config: Config, pub config: Config,
pub error: ErrorComponent, pub error: ErrorComponent,
@ -50,7 +49,6 @@ impl App {
table_status: TableStatusComponent::default(), table_status: TableStatusComponent::default(),
error: ErrorComponent::new(config.key_config), error: ErrorComponent::new(config.key_config),
focus: Focus::ConnectionList, focus: Focus::ConnectionList,
clipboard: Clipboard::new(),
pool: None, pool: None,
} }
} }
@ -262,7 +260,7 @@ impl App {
if key == self.config.key_config.copy { if key == self.config.key_config.copy {
if let Some(text) = self.record_table.table.selected_cells() { if let Some(text) = self.record_table.table.selected_cells() {
self.clipboard.store(text) copy_to_clipboard(text.as_str())?
} }
} }
@ -312,7 +310,7 @@ impl App {
if key == self.config.key_config.copy { if key == self.config.key_config.copy {
if let Some(text) = self.structure_table.selected_cells() { if let Some(text) = self.structure_table.selected_cells() {
self.clipboard.store(text) copy_to_clipboard(text.as_str())?
} }
}; };
} }

View File

@ -1,68 +1,68 @@
use copypasta::ClipboardContext; use anyhow::{anyhow, Result};
use copypasta::ClipboardProvider; #[cfg(all(target_family = "unix", not(target_os = "macos")))]
use std::ffi::OsStr;
use std::io::Write;
use std::process::{Command, Stdio};
pub struct Clipboard { fn execute_copy_command(command: Command, text: &str) -> Result<()> {
clipboard: Box<dyn ClipboardProvider>, let mut command = command;
selection: Option<Box<dyn ClipboardProvider>>,
let mut process = command
.stdin(Stdio::piped())
.stdout(Stdio::null())
.spawn()
.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;
process
.stdin
.as_mut()
.ok_or_else(|| anyhow!("`{:?}`", command))?
.write_all(text.as_bytes())
.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;
process
.wait()
.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;
Ok(())
} }
impl Clipboard { #[cfg(all(target_family = "unix", not(target_os = "macos")))]
pub fn new() -> Self { fn gen_command(path: impl AsRef<OsStr>, xclip_syntax: bool) -> Command {
Self::default() let mut c = Command::new(path);
if xclip_syntax {
c.arg("-selection");
c.arg("clipboard");
} else {
c.arg("--clipboard");
} }
c
// #[cfg(any(test, not(any(target_os = "macos", windows))))]
// pub fn new_nop() -> Self {
// Self {
// clipboard: Box::new(NopClipboardContext::new().unwrap()),
// selection: None,
// }
// }
} }
impl Default for Clipboard { #[cfg(all(target_family = "unix", not(target_os = "macos")))]
fn default() -> Self { pub fn copy_to_clipboard(string: &str) -> Result<()> {
return Self { use std::path::PathBuf;
clipboard: Box::new(ClipboardContext::new().unwrap()), use which::which;
selection: None, let (path, xclip_syntax) = which("xclip").ok().map_or_else(
}; || {
(
which("xsel").ok().unwrap_or_else(|| PathBuf::from("xsel")),
false,
)
},
|path| (path, true),
);
// #[cfg(target_os = "linux")] let cmd = gen_command(path, xclip_syntax);
// return Self { execute_copy_command(cmd, string)
// clipboard: Box::new(ClipboardContext::new().unwrap()),
// selection: Some(Box::new(
// X11ClipboardContext::<X11SelectionClipboard>::new().unwrap(),
// )),
// };
// #[cfg(not(any(target_os = "macos", windows)))]
// return Self::new_nop();
}
} }
impl Clipboard { #[cfg(target_os = "macos")]
pub fn store(&mut self, text: impl Into<String>) { pub fn copy_to_clipboard(string: &str) -> Result<()> {
let clipboard = match &mut self.selection { execute_copy_command(Command::new("pbcopy"), string)
Some(provider) => provider, }
None => &mut self.clipboard,
}; #[cfg(windows)]
pub fn copy_to_clipboard(string: &str) -> Result<()> {
clipboard.set_contents(text.into()).unwrap_or_else(|err| { execute_copy_command(Command::new("clip"), string)
panic!("Unable to store text in clipboard: {}", err);
});
}
pub fn _load(&mut self) -> String {
let clipboard = match &mut self.selection {
Some(provider) => provider,
None => &mut self.clipboard,
};
match clipboard.get_contents() {
Err(err) => {
panic!("Unable to load text from clipboard: {}", err);
}
Ok(text) => text,
}
}
} }

View File

@ -265,7 +265,7 @@ fn convert_column_value_to_string(row: &PgRow, column: &PgColumn) -> anyhow::Res
} }
if let Ok(value) = row.try_get(column_name) { if let Ok(value) = row.try_get(column_name) {
let value: Option<Vec<String>> = value; let value: Option<Vec<String>> = value;
return Ok(value.map_or("NULL".to_string(), |v| v.join(",").to_string())); return Ok(value.map_or("NULL".to_string(), |v| v.join(",")));
} }
Err(anyhow::anyhow!( Err(anyhow::anyhow!(
"column type not implemented: `{}` {}", "column type not implemented: `{}` {}",