async_readline/
lib.rs

1// TODO: http://rachid.koucha.free.fr/tech_corner/pty_pdip.html
2
3extern crate mio;
4#[macro_use]
5extern crate tokio_core;
6extern crate libc;
7extern crate nix;
8extern crate termios;
9extern crate futures;
10
11mod raw;
12
13pub use raw::*;
14
15use std::io::{self, Read, Write};
16use futures::{Async, AsyncSink};
17
18use futures::sync::BiLock;
19
20pub struct Line {
21    pub line : Vec<u8>,
22    pub text_last_nl : bool,
23}
24
25struct ReadlineInner {
26    stdin : raw::PollFd,
27    stdout : raw::PollFd,
28
29    line : Vec<u8>,
30
31    lines_ready : Vec<Vec<u8>>,
32
33    text_last_nl : bool,
34
35
36    wr_pending: Vec<u8>,
37}
38
39pub struct Lines {
40    inner : BiLock<ReadlineInner>,
41}
42
43pub struct Writer {
44    inner : BiLock<ReadlineInner>,
45}
46
47impl ReadlineInner {
48    fn clear_line(&mut self) -> io::Result<()> {
49        write!(self.wr_pending, "\x1b[2K")?;
50        write!(self.wr_pending, "\x1b[1000D")?;
51        Ok(())
52    }
53
54    fn redraw_line(&mut self) -> io::Result<()> {
55        write!(self.wr_pending, "\x1b[2K")?;
56        write!(self.wr_pending, "\x1b[1000D")?;
57        write!(self.wr_pending, "> {}", String::from_utf8_lossy(&self.line))?;
58        Ok(())
59    }
60
61    fn leave_prompt(&mut self) -> io::Result<()> {
62        self.clear_line()?;
63        self.restore_original()?;
64        if !self.text_last_nl {
65            write!(self.wr_pending, "\x1b[1B")?;
66            write!(self.wr_pending, "\x1b[1A")?;
67        }
68        Ok(())
69    }
70
71    fn enter_prompt(&mut self) -> io::Result<()> {
72        self.save_original()?;
73        if !self.text_last_nl {
74            //write!(self.wr_pending, "\x1b[1E")?;
75            write!(self.wr_pending, "\n")?;
76            self.clear_line()?;
77        }
78        Ok(())
79    }
80
81    fn save_original(&mut self) -> io::Result<()> {
82        write!(self.wr_pending, "\x1b[s")?;
83        Ok(())
84    }
85
86    fn restore_original(&mut self) -> io::Result<()> {
87        write!(self.wr_pending, "\x1b[u")?;
88        Ok(())
89    }
90
91    fn wr_pending_flush(&mut self) -> io::Result<()> {
92        let n = self.stdout.write(&self.wr_pending)?;
93        self.wr_pending.drain(..n);
94        self.stdout.flush()?;
95        Ok(())
96    }
97
98    fn handle_char(&mut self, ch : u8) {
99        match ch {
100            13 => self.lines_ready.push(std::mem::replace(&mut self.line, vec![])),
101            127 => {
102                let _ = self.line.pop();
103            },
104            _ => self.line.push(ch),
105        }
106    }
107
108    fn poll_command(&mut self) -> futures::Poll<Option<Line>, io::Error> {
109        let mut tmp_buf = [0u8; 16];
110
111        loop {
112            let _ = self.wr_pending_flush();
113
114            if let Some(line) = self.lines_ready.pop() {
115                self.clear_line()?;
116                let _ = self.wr_pending_flush();
117                return Ok(
118                    Async::Ready(Some(
119                            Line {
120                                line: line,
121                                text_last_nl: self.text_last_nl
122                            }
123                            ))
124                    )
125            }
126
127            // FIXME: 0 means EOF?
128            let bytes_read = try_nb!(self.stdin.read(&mut tmp_buf));
129
130            for ch in &tmp_buf[..bytes_read] {
131                self.handle_char(*ch)
132            }
133
134            self.redraw_line()?;
135        }
136    }
137
138    fn start_write(&mut self, mut item: Vec<u8>) -> futures::StartSend<Vec<u8>, io::Error> {
139        if item.len() > 0 {
140            self.leave_prompt()?;
141            self.text_last_nl = item[item.len() - 1] == 10;
142            self.wr_pending.append(&mut item);
143            self.enter_prompt()?;
144            self.redraw_line()?;
145        }
146        Ok(AsyncSink::Ready)
147    }
148
149    fn poll_write_complete(&mut self) -> futures::Poll<(), io::Error> {
150        loop {
151            try_nb!(self.wr_pending_flush());
152
153            if self.wr_pending.len() == 0 {
154                return Ok(Async::Ready(()));
155            }
156
157        }
158    }
159}
160
161impl futures::Stream for Lines {
162    type Item = Line;
163    type Error = io::Error;
164
165    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
166        if let Async::Ready(mut guard) = self.inner.poll_lock() {
167            guard.poll_command()
168        } else {
169            Ok(Async::NotReady)
170        }
171
172    }
173}
174
175impl futures::Sink for Writer {
176    type SinkItem = Vec<u8>;
177    type SinkError = io::Error;
178
179    fn start_send(&mut self, item: Self::SinkItem) -> futures::StartSend<Self::SinkItem, io::Error> {
180        if let Async::Ready(mut guard) = self.inner.poll_lock() {
181            guard.start_write(item)
182        } else {
183            Ok(AsyncSink::NotReady(item))
184        }
185    }
186
187    fn poll_complete(&mut self) -> futures::Poll<(), io::Error> {
188        if let Async::Ready(mut guard) = self.inner.poll_lock() {
189            guard.poll_write_complete()
190        } else {
191            Ok(Async::NotReady)
192        }
193    }
194}
195
196pub fn init(stdin : PollFd, stdout : PollFd) -> (Lines, Writer) {
197    let mut inner = ReadlineInner {
198        stdin: stdin,
199        stdout : stdout,
200        line: vec![],
201        text_last_nl: true,
202        wr_pending : vec!(),
203        lines_ready : vec![],
204    };
205
206    let _ = inner.enter_prompt();
207
208    let (l1, l2) = BiLock::new(inner);
209
210
211
212    let writer = Writer { inner: l1 };
213    let lines = Lines { inner: l2 };
214    (lines, writer)
215}
216
217#[cfg(test)]
218mod tests {
219    #[test]
220    fn it_works() {
221    }
222}