Implement Handler::identify_terminal for Term

The identify_terminal function signature had to change to support
writing to the terminal before processing additional input.
This commit is contained in:
Joe Wilm 2016-12-04 15:48:30 -08:00
parent 61c1e37c46
commit ed48d08c03
4 changed files with 79 additions and 22 deletions

View File

@ -31,6 +31,7 @@
//! should be, feel free to add it. Please try not to become overzealous and adding support for
//! sequences only used by folks trapped in 1988.
use std::ops::Range;
use std::io;
use vte;
@ -51,18 +52,24 @@ struct ProcessorState;
///
/// Processor creates a Performer when running advance and passes the Performer
/// to vte::Parser.
struct Performer<'a, H: Handler + TermInfo + 'a> {
struct Performer<'a, H: Handler + TermInfo + 'a, W: io::Write + 'a> {
_state: &'a mut ProcessorState,
handler: &'a mut H
handler: &'a mut H,
writer: &'a mut W
}
impl<'a, H: Handler + TermInfo + 'a> Performer<'a, H> {
impl<'a, H: Handler + TermInfo + 'a, W: io::Write> Performer<'a, H, W> {
/// Create a performer
#[inline]
pub fn new<'b>(state: &'b mut ProcessorState, handler: &'b mut H) -> Performer<'b, H> {
pub fn new<'b>(
state: &'b mut ProcessorState,
handler: &'b mut H,
writer: &'b mut W,
) -> Performer<'b, H, W> {
Performer {
_state: state,
handler: handler
handler: handler,
writer: writer,
}
}
}
@ -76,8 +83,16 @@ impl Processor {
}
#[inline]
pub fn advance<H: Handler + TermInfo>(&mut self, handler: &mut H, byte: u8) {
let mut performer = Performer::new(&mut self.state, handler);
pub fn advance<H, W>(
&mut self,
handler: &mut H,
byte: u8,
writer: &mut W
)
where H: Handler + TermInfo,
W: io::Write
{
let mut performer = Performer::new(&mut self.state, handler, writer);
self.parser.advance(&mut performer, byte);
}
}
@ -116,7 +131,9 @@ pub trait Handler {
fn move_down(&mut self, Line) {}
/// Identify the terminal (should write back to the pty stream)
fn identify_terminal(&mut self) {}
///
/// TODO this should probably return an io::Result
fn identify_terminal<W: io::Write>(&mut self, &mut W) {}
/// Move cursor forward `cols`
fn move_forward(&mut self, Column) {}
@ -415,7 +432,10 @@ pub enum Attr {
Background(Color),
}
impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
impl<'a, H, W> vte::Perform for Performer<'a, H, W>
where H: Handler + TermInfo + 'a,
W: io::Write + 'a
{
#[inline]
fn print(&mut self, c: char) {
self.handler.input(c);
@ -432,7 +452,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
C0::SUB => self.handler.substitute(),
C1::NEL => self.handler.newline(),
C1::HTS => self.handler.set_horizontal_tabstop(),
C1::DECID => self.handler.identify_terminal(),
C1::DECID => self.handler.identify_terminal(self.writer),
_ => err_println!("[unhandled] execute byte={:02x}", byte)
}
}
@ -469,9 +489,16 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
}
#[inline]
fn csi_dispatch(&mut self, args: &[i64], intermediates: &[u8], _ignore: bool, action: char) {
fn csi_dispatch(
&mut self,
args: &[i64],
intermediates: &[u8],
_ignore: bool,
action: char
) {
let private = intermediates.get(0).map(|b| *b == b'?').unwrap_or(false);
let handler = &mut self.handler;
let writer = &mut self.writer;
macro_rules! unhandled {
@ -500,7 +527,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
handler.move_up(Line(arg_or_default!(idx: 0, default: 1) as usize));
},
'B' | 'e' => handler.move_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
'c' => handler.identify_terminal(),
'c' => handler.identify_terminal(writer),
'C' | 'a' => handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
'D' => handler.move_backward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
'E' => handler.move_down_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
@ -650,7 +677,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
i += 1; // C-for expr
}
}
'n' => handler.identify_terminal(),
'n' => handler.identify_terminal(writer),
'r' => {
if private {
unhandled!();
@ -679,7 +706,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
b'E' => self.handler.newline(),
b'H' => self.handler.set_horizontal_tabstop(),
b'M' => self.handler.reverse_index(),
b'Z' => self.handler.identify_terminal(),
b'Z' => self.handler.identify_terminal(self.writer),
b'c' => self.handler.reset_state(),
b'7' => self.handler.save_cursor_position(),
b'8' => self.handler.restore_cursor_position(),
@ -899,10 +926,26 @@ pub mod C1 {
// Byte sequences used in these tests are recording of pty stdout.
#[cfg(test)]
mod tests {
use std::io;
use index::{Line, Column};
use super::{Processor, Handler, Attr, TermInfo, Color};
use ::Rgb;
/// The /dev/null of io::Write
struct Void;
impl io::Write for Void {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
Ok(bytes.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[derive(Default)]
struct AttrHandler {
attr: Option<Attr>,
@ -934,7 +977,7 @@ mod tests {
let mut handler = AttrHandler::default();
for byte in &BYTES[..] {
parser.advance(&mut handler, *byte);
parser.advance(&mut handler, *byte, &mut Void);
}
assert_eq!(handler.attr, Some(Attr::Bold));
@ -951,7 +994,7 @@ mod tests {
let mut handler = AttrHandler::default();
for byte in &BYTES[..] {
parser.advance(&mut handler, *byte);
parser.advance(&mut handler, *byte, &mut Void);
}
let spec = Rgb {
@ -986,7 +1029,7 @@ mod tests {
let mut parser = Processor::new();
for byte in &BYTES[..] {
parser.advance(&mut handler, *byte);
parser.advance(&mut handler, *byte, &mut Void);
}
}
}

View File

@ -189,7 +189,7 @@ impl<Io> EventLoop<Io>
let mut terminal = self.terminal.lock();
for byte in &buf[..got] {
state.parser.advance(&mut *terminal, *byte);
state.parser.advance(&mut *terminal, *byte, &mut self.pty);
}
terminal.dirty = true;

View File

@ -16,6 +16,7 @@
use std::ops::{Deref, Range};
use std::ptr;
use std::cmp;
use std::io;
use ansi::{self, Attr, Handler};
use grid::{Grid, ClearRegion};
@ -557,8 +558,8 @@ impl ansi::Handler for Term {
}
#[inline]
fn identify_terminal(&mut self) {
err_println!("[unimplemented] identify_terminal");
fn identify_terminal<W: io::Write>(&mut self, writer: &mut W) {
let _ = writer.write_all("\x1b[?6c".as_bytes());
}
#[inline]

View File

@ -4,7 +4,7 @@ extern crate serde_json;
/// ref tests
mod reference {
use std::fs::File;
use std::io::Read;
use std::io::{self, Read};
use std::path::Path;
use serde_json as json;
@ -15,6 +15,19 @@ mod reference {
use alacritty::term::SizeInfo;
use alacritty::ansi;
/// The /dev/null of io::Write
struct Void;
impl io::Write for Void {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
Ok(bytes.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
macro_rules! ref_file {
($ref_name:ident, $file:expr) => {
concat!(
@ -59,7 +72,7 @@ mod reference {
let mut parser = ansi::Processor::new();
for byte in recording {
parser.advance(&mut terminal, byte);
parser.advance(&mut terminal, byte, &mut Void);
}
assert_eq!(grid, *terminal.grid());