2018-08-07 15:01:15 +03:00
/*
* meli - ui crate .
*
* Copyright 2017 - 2018 Manos Pitsidianakis
*
* This file is part of meli .
*
* meli is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* meli is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with meli . If not , see < http ://www.gnu.org/licenses/>.
* /
2019-03-03 14:24:15 +02:00
use super ::* ;
2018-08-06 16:53:23 +03:00
use chan ;
2018-09-09 17:09:45 +03:00
use std ::fmt ;
2018-08-06 16:53:23 +03:00
use std ::io ;
2018-09-09 17:09:45 +03:00
use termion ::event ::Event as TermionEvent ;
2018-08-07 15:01:15 +03:00
use termion ::event ::Key as TermionKey ;
use termion ::input ::TermRead ;
2018-08-06 16:53:23 +03:00
2019-05-13 22:05:00 +03:00
#[ derive(Debug, PartialEq, Eq, Clone) ]
2018-08-06 16:53:23 +03:00
pub enum Key {
/// Backspace.
Backspace ,
/// Left arrow.
Left ,
/// Right arrow.
Right ,
/// Up arrow.
Up ,
/// Down arrow.
Down ,
/// Home key.
Home ,
/// End key.
End ,
/// Page Up key.
PageUp ,
/// Page Down key.
PageDown ,
/// Delete key.
Delete ,
/// Insert key.
Insert ,
/// Function keys.
///
/// Only function keys 1 through 12 are supported.
F ( u8 ) ,
/// Normal character.
Char ( char ) ,
/// Alt modified character.
Alt ( char ) ,
/// Ctrl modified character.
///
/// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
Ctrl ( char ) ,
/// Null byte.
Null ,
/// Esc key.
Esc ,
2018-09-09 17:09:45 +03:00
Paste ( String ) ,
}
2019-03-30 21:21:17 +02:00
impl fmt ::Display for Key {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2019-06-18 21:13:58 +03:00
use crate ::Key ::* ;
2019-03-30 21:21:17 +02:00
match self {
F ( n ) = > write! ( f , " F{} " , n ) ,
Char ( '\t' ) = > write! ( f , " Tab " ) ,
Char ( '\n' ) = > write! ( f , " Enter " ) ,
Char ( c ) = > write! ( f , " {} " , c ) ,
Alt ( c ) = > write! ( f , " M-{} " , c ) ,
Ctrl ( c ) = > write! ( f , " C-{} " , c ) ,
Paste ( _ ) = > write! ( f , " Pasted buf " ) ,
2019-04-04 15:29:33 +03:00
Null = > write! ( f , " Null byte " ) ,
Esc = > write! ( f , " Esc " ) ,
Backspace = > write! ( f , " Backspace " ) ,
Left = > write! ( f , " Left " ) ,
Right = > write! ( f , " Right " ) ,
Up = > write! ( f , " Up " ) ,
Down = > write! ( f , " Down " ) ,
Home = > write! ( f , " Home " ) ,
End = > write! ( f , " End " ) ,
PageUp = > write! ( f , " PageUp " ) ,
PageDown = > write! ( f , " PageDown " ) ,
Delete = > write! ( f , " Delete " ) ,
Insert = > write! ( f , " Insert " ) ,
2019-03-30 21:21:17 +02:00
}
}
}
2018-09-09 17:09:45 +03:00
impl < ' a > From < & ' a String > for Key {
fn from ( v : & ' a String ) -> Self {
Key ::Paste ( v . to_string ( ) )
}
2018-08-06 16:53:23 +03:00
}
impl From < TermionKey > for Key {
fn from ( k : TermionKey ) -> Self {
match k {
TermionKey ::Backspace = > Key ::Backspace ,
TermionKey ::Left = > Key ::Left ,
TermionKey ::Right = > Key ::Right ,
TermionKey ::Up = > Key ::Up ,
TermionKey ::Down = > Key ::Down ,
TermionKey ::Home = > Key ::Home ,
TermionKey ::End = > Key ::End ,
TermionKey ::PageUp = > Key ::PageUp ,
TermionKey ::PageDown = > Key ::PageDown ,
TermionKey ::Delete = > Key ::Delete ,
TermionKey ::Insert = > Key ::Insert ,
TermionKey ::F ( u ) = > Key ::F ( u ) ,
TermionKey ::Char ( c ) = > Key ::Char ( c ) ,
TermionKey ::Alt ( c ) = > Key ::Alt ( c ) ,
TermionKey ::Ctrl ( c ) = > Key ::Ctrl ( c ) ,
TermionKey ::Null = > Key ::Null ,
TermionKey ::Esc = > Key ::Esc ,
_ = > Key ::Char ( ' ' ) ,
}
}
}
2019-04-29 10:54:40 +03:00
impl PartialEq < Key > for & Key {
fn eq ( & self , other : & Key ) -> bool {
* * self = = * other
}
}
2018-09-09 17:09:45 +03:00
#[ derive(PartialEq) ]
enum InputMode {
Normal ,
Paste ,
}
2018-08-06 16:53:23 +03:00
/*
* If we fork ( for example start $EDITOR ) we want the input - thread to stop reading from stdin . The
* best way I came up with right now is to send a signal to the thread that is read in the first
* input in stdin after the fork , and then the thread kills itself . The parent process spawns a new
* input - thread when the child returns .
*
* The main loop uses try_wait_on_child ( ) to check if child has exited .
* /
pub fn get_events (
stdin : io ::Stdin ,
mut closure : impl FnMut ( Key ) ,
mut exit : impl FnMut ( ) ,
2018-08-07 15:01:15 +03:00
rx : & chan ::Receiver < bool > ,
2019-02-25 11:11:56 +02:00
) {
2018-09-09 17:09:45 +03:00
let mut input_mode = InputMode ::Normal ;
let mut paste_buf = String ::with_capacity ( 256 ) ;
for c in stdin . events ( ) {
2018-08-06 16:53:23 +03:00
chan_select! {
default = > { } ,
rx . recv ( ) -> val = > {
if let Some ( true ) = val {
exit ( ) ;
return ;
} else if let Some ( false ) = val {
return ;
}
}
} ;
2018-09-09 17:09:45 +03:00
match c {
Ok ( TermionEvent ::Key ( k ) ) if input_mode = = InputMode ::Normal = > {
closure ( Key ::from ( k ) ) ;
}
Ok ( TermionEvent ::Key ( TermionKey ::Char ( k ) ) ) if input_mode = = InputMode ::Paste = > {
paste_buf . push ( k ) ;
}
Ok ( TermionEvent ::Unsupported ( ref k ) ) if k . as_slice ( ) = = BRACKET_PASTE_START = > {
input_mode = InputMode ::Paste ;
}
Ok ( TermionEvent ::Unsupported ( ref k ) ) if k . as_slice ( ) = = BRACKET_PASTE_END = > {
input_mode = InputMode ::Normal ;
let ret = Key ::from ( & paste_buf ) ;
paste_buf . clear ( ) ;
closure ( ret ) ;
}
_ = > { } // Mouse events or errors.
2018-08-06 16:53:23 +03:00
}
}
}
2018-09-09 17:09:45 +03:00
/*
* CSI events we use
* /
// Some macros taken from termion:
/// Create a CSI-introduced sequence.
macro_rules ! csi {
( $( $l :expr ) , * ) = > { concat! ( " \x1B [ " , $( $l ) , * ) } ;
}
/// Derive a CSI sequence struct.
macro_rules ! derive_csi_sequence {
2019-03-26 15:27:02 +02:00
( $( #[ $outer:meta ] ) *
( $name :ident , $value :expr ) ) = > {
$( #[ $outer ] ) *
2018-09-09 17:09:45 +03:00
#[ derive(Copy, Clone) ]
pub struct $name ;
impl fmt ::Display for $name {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( f , csi! ( $value ) )
}
}
impl AsRef < [ u8 ] > for $name {
fn as_ref ( & self ) -> & 'static [ u8 ] {
csi! ( $value ) . as_bytes ( )
}
}
impl AsRef < str > for $name {
fn as_ref ( & self ) -> & 'static str {
csi! ( $value )
}
}
} ;
}
2019-03-26 19:53:39 +02:00
derive_csi_sequence! (
#[ 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) " ]
( BracketModeStart , " ?2004h " )
) ;
derive_csi_sequence! (
#[ 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) " ]
( BracketModeEnd , " ?2003l " )
) ;
2018-09-09 17:09:45 +03:00
pub const BRACKET_PASTE_START : & [ u8 ] = b " \x1B [200~ " ;
pub const BRACKET_PASTE_END : & [ u8 ] = b " \x1B [201~ " ;
2019-03-03 14:24:15 +02:00
2019-03-03 22:11:15 +02:00
const FIELDS : & [ & str ] = & [ ] ;
2019-03-03 14:24:15 +02:00
impl < ' de > Deserialize < ' de > for Key {
fn deserialize < D > ( deserializer : D ) -> Result < Self , D ::Error >
2019-03-14 12:19:25 +02:00
where
D : Deserializer < ' de > ,
{
struct KeyVisitor ;
2019-03-03 14:24:15 +02:00
2019-03-14 12:19:25 +02:00
impl < ' de > Visitor < ' de > for KeyVisitor {
type Value = Key ;
2019-03-03 14:24:15 +02:00
2019-03-14 12:19:25 +02:00
fn expecting ( & self , formatter : & mut fmt ::Formatter ) -> fmt ::Result {
formatter . write_str ( " `secs` or `nanos` " )
2019-03-03 14:24:15 +02:00
}
2019-03-14 12:19:25 +02:00
fn visit_str < E > ( self , value : & str ) -> Result < Key , E >
where
E : de ::Error ,
{
match value {
" Backspace " = > Ok ( Key ::Backspace ) ,
" Left " = > Ok ( Key ::Left ) ,
" Right " = > Ok ( Key ::Right ) ,
" Up " = > Ok ( Key ::Up ) ,
" Down " = > Ok ( Key ::Down ) ,
" Home " = > Ok ( Key ::Home ) ,
" End " = > Ok ( Key ::End ) ,
" PageUp " = > Ok ( Key ::PageUp ) ,
" PageDown " = > Ok ( Key ::PageDown ) ,
" Delete " = > Ok ( Key ::Delete ) ,
" Insert " = > Ok ( Key ::Insert ) ,
" Esc " = > Ok ( Key ::Esc ) ,
ref s if s . len ( ) = = 1 = > Ok ( Key ::Char ( s . chars ( ) . nth ( 0 ) . unwrap ( ) ) ) ,
_ = > Err ( de ::Error ::unknown_field ( value , FIELDS ) ) ,
}
}
2019-03-03 14:24:15 +02:00
}
2019-03-14 12:19:25 +02:00
deserializer . deserialize_identifier ( KeyVisitor )
}
2019-03-03 14:24:15 +02:00
}