mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
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:
parent
61c1e37c46
commit
ed48d08c03
4 changed files with 79 additions and 22 deletions
77
src/ansi.rs
77
src/ansi.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]
|
||||
|
|
17
tests/ref.rs
17
tests/ref.rs
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue