You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
8.4KB

  1. /*
  2. * meli - ui crate.
  3. *
  4. * Copyright 2017-2018 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. use super::*;
  22. use chan;
  23. use std::fmt;
  24. use std::io;
  25. use termion::event::Event as TermionEvent;
  26. use termion::event::Key as TermionKey;
  27. use termion::input::TermRead;
  28. #[derive(Debug, PartialEq, Eq, Clone)]
  29. pub enum Key {
  30. /// Backspace.
  31. Backspace,
  32. /// Left arrow.
  33. Left,
  34. /// Right arrow.
  35. Right,
  36. /// Up arrow.
  37. Up,
  38. /// Down arrow.
  39. Down,
  40. /// Home key.
  41. Home,
  42. /// End key.
  43. End,
  44. /// Page Up key.
  45. PageUp,
  46. /// Page Down key.
  47. PageDown,
  48. /// Delete key.
  49. Delete,
  50. /// Insert key.
  51. Insert,
  52. /// Function keys.
  53. ///
  54. /// Only function keys 1 through 12 are supported.
  55. F(u8),
  56. /// Normal character.
  57. Char(char),
  58. /// Alt modified character.
  59. Alt(char),
  60. /// Ctrl modified character.
  61. ///
  62. /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
  63. Ctrl(char),
  64. /// Null byte.
  65. Null,
  66. /// Esc key.
  67. Esc,
  68. Paste(String),
  69. }
  70. impl fmt::Display for Key {
  71. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  72. use crate::Key::*;
  73. match self {
  74. F(n) => write!(f, "F{}", n),
  75. Char('\t') => write!(f, "Tab"),
  76. Char('\n') => write!(f, "Enter"),
  77. Char(c) => write!(f, "{}", c),
  78. Alt(c) => write!(f, "M-{}", c),
  79. Ctrl(c) => write!(f, "C-{}", c),
  80. Paste(_) => write!(f, "Pasted buf"),
  81. Null => write!(f, "Null byte"),
  82. Esc => write!(f, "Esc"),
  83. Backspace => write!(f, "Backspace"),
  84. Left => write!(f, "Left"),
  85. Right => write!(f, "Right"),
  86. Up => write!(f, "Up"),
  87. Down => write!(f, "Down"),
  88. Home => write!(f, "Home"),
  89. End => write!(f, "End"),
  90. PageUp => write!(f, "PageUp"),
  91. PageDown => write!(f, "PageDown"),
  92. Delete => write!(f, "Delete"),
  93. Insert => write!(f, "Insert"),
  94. }
  95. }
  96. }
  97. impl<'a> From<&'a String> for Key {
  98. fn from(v: &'a String) -> Self {
  99. Key::Paste(v.to_string())
  100. }
  101. }
  102. impl From<TermionKey> for Key {
  103. fn from(k: TermionKey) -> Self {
  104. match k {
  105. TermionKey::Backspace => Key::Backspace,
  106. TermionKey::Left => Key::Left,
  107. TermionKey::Right => Key::Right,
  108. TermionKey::Up => Key::Up,
  109. TermionKey::Down => Key::Down,
  110. TermionKey::Home => Key::Home,
  111. TermionKey::End => Key::End,
  112. TermionKey::PageUp => Key::PageUp,
  113. TermionKey::PageDown => Key::PageDown,
  114. TermionKey::Delete => Key::Delete,
  115. TermionKey::Insert => Key::Insert,
  116. TermionKey::F(u) => Key::F(u),
  117. TermionKey::Char(c) => Key::Char(c),
  118. TermionKey::Alt(c) => Key::Alt(c),
  119. TermionKey::Ctrl(c) => Key::Ctrl(c),
  120. TermionKey::Null => Key::Null,
  121. TermionKey::Esc => Key::Esc,
  122. _ => Key::Char(' '),
  123. }
  124. }
  125. }
  126. impl PartialEq<Key> for &Key {
  127. fn eq(&self, other: &Key) -> bool {
  128. **self == *other
  129. }
  130. }
  131. #[derive(PartialEq)]
  132. enum InputMode {
  133. Normal,
  134. Paste,
  135. }
  136. /*
  137. * If we fork (for example start $EDITOR) we want the input-thread to stop reading from stdin. The
  138. * best way I came up with right now is to send a signal to the thread that is read in the first
  139. * input in stdin after the fork, and then the thread kills itself. The parent process spawns a new
  140. * input-thread when the child returns.
  141. *
  142. * The main loop uses try_wait_on_child() to check if child has exited.
  143. */
  144. pub fn get_events(
  145. stdin: io::Stdin,
  146. mut closure: impl FnMut(Key),
  147. mut exit: impl FnMut(),
  148. rx: &chan::Receiver<bool>,
  149. ) {
  150. let mut input_mode = InputMode::Normal;
  151. let mut paste_buf = String::with_capacity(256);
  152. for c in stdin.events() {
  153. chan_select! {
  154. default => {},
  155. rx.recv() -> val => {
  156. if let Some(true) = val {
  157. exit();
  158. return;
  159. } else if let Some(false) = val {
  160. return;
  161. }
  162. }
  163. };
  164. match c {
  165. Ok(TermionEvent::Key(k)) if input_mode == InputMode::Normal => {
  166. closure(Key::from(k));
  167. }
  168. Ok(TermionEvent::Key(TermionKey::Char(k))) if input_mode == InputMode::Paste => {
  169. paste_buf.push(k);
  170. }
  171. Ok(TermionEvent::Unsupported(ref k)) if k.as_slice() == BRACKET_PASTE_START => {
  172. input_mode = InputMode::Paste;
  173. }
  174. Ok(TermionEvent::Unsupported(ref k)) if k.as_slice() == BRACKET_PASTE_END => {
  175. input_mode = InputMode::Normal;
  176. let ret = Key::from(&paste_buf);
  177. paste_buf.clear();
  178. closure(ret);
  179. }
  180. _ => {} // Mouse events or errors.
  181. }
  182. }
  183. }
  184. /*
  185. * CSI events we use
  186. */
  187. // Some macros taken from termion:
  188. /// Create a CSI-introduced sequence.
  189. macro_rules! csi {
  190. ($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) };
  191. }
  192. /// Derive a CSI sequence struct.
  193. macro_rules! derive_csi_sequence {
  194. ($(#[$outer:meta])*
  195. ($name:ident, $value:expr)) => {
  196. $(#[$outer])*
  197. #[derive(Copy, Clone)]
  198. pub struct $name;
  199. impl fmt::Display for $name {
  200. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  201. write!(f, csi!($value))
  202. }
  203. }
  204. impl AsRef<[u8]> for $name {
  205. fn as_ref(&self) -> &'static [u8] {
  206. csi!($value).as_bytes()
  207. }
  208. }
  209. impl AsRef<str> for $name {
  210. fn as_ref(&self) -> &'static str {
  211. csi!($value)
  212. }
  213. }
  214. };
  215. }
  216. derive_csi_sequence!(
  217. #[doc = "Empty struct with a Display implementation that returns the byte sequence to start [Bracketed Paste Mode](http://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode)"]
  218. (BracketModeStart, "?2004h")
  219. );
  220. derive_csi_sequence!(
  221. #[doc = "Empty struct with a Display implementation that returns the byte sequence to end [Bracketed Paste Mode](http://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode)"]
  222. (BracketModeEnd, "?2003l")
  223. );
  224. pub const BRACKET_PASTE_START: &[u8] = b"\x1B[200~";
  225. pub const BRACKET_PASTE_END: &[u8] = b"\x1B[201~";
  226. const FIELDS: &[&str] = &[];
  227. impl<'de> Deserialize<'de> for Key {
  228. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  229. where
  230. D: Deserializer<'de>,
  231. {
  232. struct KeyVisitor;
  233. impl<'de> Visitor<'de> for KeyVisitor {
  234. type Value = Key;
  235. fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
  236. formatter.write_str("`secs` or `nanos`")
  237. }
  238. fn visit_str<E>(self, value: &str) -> Result<Key, E>
  239. where
  240. E: de::Error,
  241. {
  242. match value {
  243. "Backspace" => Ok(Key::Backspace),
  244. "Left" => Ok(Key::Left),
  245. "Right" => Ok(Key::Right),
  246. "Up" => Ok(Key::Up),
  247. "Down" => Ok(Key::Down),
  248. "Home" => Ok(Key::Home),
  249. "End" => Ok(Key::End),
  250. "PageUp" => Ok(Key::PageUp),
  251. "PageDown" => Ok(Key::PageDown),
  252. "Delete" => Ok(Key::Delete),
  253. "Insert" => Ok(Key::Insert),
  254. "Esc" => Ok(Key::Esc),
  255. ref s if s.len() == 1 => Ok(Key::Char(s.chars().nth(0).unwrap())),
  256. _ => Err(de::Error::unknown_field(value, FIELDS)),
  257. }
  258. }
  259. }
  260. deserializer.deserialize_identifier(KeyVisitor)
  261. }
  262. }