/src/edit_buffer/clipboard.rs

https://github.com/akiradeveloper/ijk · Rust · 162 lines · 148 code · 13 blank · 1 comment · 9 complexity · 64b7faa642864d4935825a37cb0f8900 MD5 · raw file

  1. // https://github.com/hatoo/Accepted
  2. use std::io::{Read, Write};
  3. use std::process;
  4. use std::process::Command;
  5. use std::sync::{Arc, Mutex};
  6. use lazy_static::lazy_static;
  7. use super::BufElem;
  8. lazy_static! {
  9. static ref SINGLETON: Clipboard = Clipboard::new();
  10. }
  11. #[derive(Clone)]
  12. pub enum Type {
  13. Range(Vec<BufElem>),
  14. Line(Vec<BufElem>),
  15. }
  16. fn to_str(x: &[BufElem]) -> String {
  17. let mut s = String::new();
  18. for e in x {
  19. let c = match *e {
  20. BufElem::Char(c) => c,
  21. BufElem::Eol => '\n',
  22. };
  23. s.push(c)
  24. }
  25. s
  26. }
  27. fn from_str(x: &str) -> Vec<BufElem> {
  28. let mut v = vec![];
  29. for c in x.chars() {
  30. let e = match c {
  31. '\n' => BufElem::Eol,
  32. c => BufElem::Char(c),
  33. };
  34. v.push(e)
  35. }
  36. v
  37. }
  38. struct ClipboardImpl {
  39. x: Option<Type>,
  40. }
  41. impl ClipboardImpl {
  42. fn new() -> Self {
  43. Self { x: None }
  44. }
  45. fn copy(&mut self, x: Type) {
  46. let v = match &x {
  47. Type::Range(a) => a,
  48. Type::Line(a) => a,
  49. };
  50. clipboard_copy(&to_str(&v));
  51. self.x = Some(x.clone())
  52. }
  53. fn paste(&mut self) -> Option<Type> {
  54. self.x.clone()
  55. }
  56. }
  57. pub struct Clipboard {
  58. imp: Arc<Mutex<ClipboardImpl>>,
  59. }
  60. impl Clipboard {
  61. fn new() -> Self {
  62. Self {
  63. imp: Arc::new(Mutex::new(ClipboardImpl::new()))
  64. }
  65. }
  66. }
  67. fn clipboard_copy(s: &str) -> bool {
  68. if let Ok(mut p) = Command::new("pbcopy")
  69. .stdin(process::Stdio::piped())
  70. .spawn()
  71. .or_else(|_| {
  72. Command::new("win32yank")
  73. .arg("-i")
  74. .stdin(process::Stdio::piped())
  75. .spawn()
  76. })
  77. .or_else(|_| {
  78. Command::new("win32yank.exe")
  79. .arg("-i")
  80. .stdin(process::Stdio::piped())
  81. .spawn()
  82. })
  83. .or_else(|_| {
  84. Command::new("xsel")
  85. .arg("-bi")
  86. .stdin(process::Stdio::piped())
  87. .spawn()
  88. })
  89. .or_else(|_| {
  90. Command::new("xclip")
  91. .arg("-i")
  92. .stdin(process::Stdio::piped())
  93. .spawn()
  94. })
  95. {
  96. if let Some(mut stdin) = p.stdin.take() {
  97. write!(stdin, "{}", s).unwrap();
  98. std::thread::sleep(std::time::Duration::from_millis(10));
  99. return true;
  100. }
  101. }
  102. false
  103. }
  104. fn clipboard_paste() -> Option<String> {
  105. if let Ok(mut p) = Command::new("pbpaste")
  106. .stdout(process::Stdio::piped())
  107. .spawn()
  108. .or_else(|_| {
  109. Command::new("win32yank")
  110. .arg("-o")
  111. .stdout(process::Stdio::piped())
  112. .spawn()
  113. })
  114. .or_else(|_| {
  115. Command::new("win32yank.exe")
  116. .arg("-o")
  117. .stdout(process::Stdio::piped())
  118. .spawn()
  119. })
  120. .or_else(|_| {
  121. Command::new("xsel")
  122. .arg("-bo")
  123. .stdout(process::Stdio::piped())
  124. .spawn()
  125. })
  126. .or_else(|_| {
  127. Command::new("xclip")
  128. .arg("-o")
  129. .stdout(process::Stdio::piped())
  130. .spawn()
  131. })
  132. {
  133. if let Some(mut stdout) = p.stdout.take() {
  134. let mut buf = String::new();
  135. stdout.read_to_string(&mut buf).ok()?;
  136. return Some(buf);
  137. }
  138. }
  139. None
  140. }
  141. pub fn copy(x: Type) {
  142. SINGLETON.imp.lock().unwrap().copy(x);
  143. }
  144. pub fn paste() -> Option<Type> {
  145. SINGLETON.imp.lock().unwrap().paste()
  146. }
  147. pub fn paste_system() -> Option<Vec<BufElem>> {
  148. clipboard_paste().map(|x| from_str(&x))
  149. }