mirror of
https://github.com/wez/wezterm.git
synced 2024-11-23 23:21:08 +03:00
hide AnswerBack from the public interface
This felt a bit repeatey and it pre-dated the TerminalHost trait. I'd like to remove it completely but there are some frustrating and fiddly lifetime concerns with mutable TerminalHost reference so I'm hiding it from the public interface and bridging it the answerback stream into the host at the bottom of the advance_bytes method for now.
This commit is contained in:
parent
52ba033ea7
commit
7ad2468937
15
src/xwin.rs
15
src/xwin.rs
@ -186,6 +186,10 @@ impl<'a> term::TerminalHost for Host<'a> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: &str) {
|
||||
self.window.set_title(title);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TerminalWindow<'a> {
|
||||
@ -861,16 +865,7 @@ impl<'a> TerminalWindow<'a> {
|
||||
loop {
|
||||
match self.host.pty.read(&mut buf) {
|
||||
Ok(size) => {
|
||||
for answer in self.terminal.advance_bytes(&buf[0..size]) {
|
||||
match answer {
|
||||
term::AnswerBack::WriteToPty(response) => {
|
||||
self.host.pty.write(&response).ok(); // discard error
|
||||
}
|
||||
term::AnswerBack::TitleChanged(title) => {
|
||||
self.host.window.set_title(&title);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.terminal.advance_bytes(&buf[0..size], &mut self.host);
|
||||
if size < BUFSIZE {
|
||||
// If we had a short read then there is no more
|
||||
// data to read right now; we'll get called again
|
||||
|
@ -13,6 +13,9 @@ pub trait TerminalHost {
|
||||
|
||||
/// Adjust the contents of the clipboard
|
||||
fn set_clipboard(&mut self, clip: Option<String>) -> Result<(), Error>;
|
||||
|
||||
/// Change the title of the window
|
||||
fn set_title(&mut self, title: &str);
|
||||
}
|
||||
|
||||
pub struct Terminal {
|
||||
@ -39,7 +42,7 @@ impl DerefMut for Terminal {
|
||||
/// When the terminal parser needs to convey a response
|
||||
/// back to the caller, this enum holds that response
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AnswerBack {
|
||||
pub(crate) enum AnswerBack {
|
||||
/// Some data to send back to the application on
|
||||
/// the slave end of the pty.
|
||||
WriteToPty(Vec<u8>),
|
||||
@ -57,15 +60,20 @@ impl Terminal {
|
||||
}
|
||||
|
||||
/// Feed the terminal parser a slice of bytes of input.
|
||||
/// The return value is a (likely empty most of the time)
|
||||
/// sequence of AnswerBack objects that may need to be rendered
|
||||
/// in the UI or sent back to the client on the slave side of
|
||||
/// the pty.
|
||||
pub fn advance_bytes<B: AsRef<[u8]>>(&mut self, bytes: B) -> Vec<AnswerBack> {
|
||||
pub fn advance_bytes<B: AsRef<[u8]>>(&mut self, bytes: B, host: &mut TerminalHost) {
|
||||
let bytes = bytes.as_ref();
|
||||
for b in bytes.iter() {
|
||||
self.parser.advance(&mut self.state, *b);
|
||||
}
|
||||
self.state.drain_answerback()
|
||||
for answer in self.state.drain_answerback() {
|
||||
match answer {
|
||||
AnswerBack::WriteToPty(response) => {
|
||||
host.writer().write(&response).ok(); // discard error
|
||||
}
|
||||
AnswerBack::TitleChanged(title) => {
|
||||
host.set_title(&title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -678,7 +678,7 @@ impl TerminalState {
|
||||
self.answerback.push(AnswerBack::WriteToPty(buf.to_vec()));
|
||||
}
|
||||
|
||||
pub fn drain_answerback(&mut self) -> Vec<AnswerBack> {
|
||||
pub(crate) fn drain_answerback(&mut self) -> Vec<AnswerBack> {
|
||||
self.answerback.drain(0..).collect()
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,38 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct TestHost {
|
||||
title: String,
|
||||
clip: Option<String>,
|
||||
}
|
||||
|
||||
impl TestHost {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
impl TerminalHost for TestHost {
|
||||
fn set_title(&mut self, title: &str) {
|
||||
self.title = title.into();
|
||||
}
|
||||
|
||||
fn set_clipboard(&mut self, clip: Option<String>) -> Result<(), Error> {
|
||||
self.clip = clip;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_clipboard(&mut self) -> Result<String, Error> {
|
||||
self.clip.as_ref().map(|c| c.clone()).ok_or_else(|| {
|
||||
failure::err_msg("no clipboard")
|
||||
})
|
||||
}
|
||||
|
||||
fn writer(&mut self) -> &mut std::io::Write {
|
||||
panic!("no writer support in TestHost");
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_cursor_pos {
|
||||
($term:expr, $x:expr, $y:expr) => {
|
||||
assert_cursor_pos!($term, $x, $y,
|
||||
@ -76,47 +108,47 @@ fn assert_lines_equal(lines: &[Line], expect_lines: &[Line], compare: Compare) {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_mode(term: &mut Terminal, mode: &str, enable: bool) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(mode);
|
||||
term.advance_bytes(if enable { b"h" } else { b"l" });
|
||||
fn set_mode(term: &mut Terminal, host: &mut TerminalHost, mode: &str, enable: bool) {
|
||||
term.advance_bytes(CSI, host);
|
||||
term.advance_bytes(mode, host);
|
||||
term.advance_bytes(if enable { b"h" } else { b"l" }, host);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_scroll_region(term: &mut Terminal, top: usize, bottom: usize) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(format!("{};{}r", top + 1, bottom + 1));
|
||||
fn set_scroll_region(term: &mut Terminal, host: &mut TerminalHost, top: usize, bottom: usize) {
|
||||
term.advance_bytes(CSI, host);
|
||||
term.advance_bytes(format!("{};{}r", top + 1, bottom + 1), host);
|
||||
}
|
||||
|
||||
fn delete_lines(term: &mut Terminal, n: usize) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(format!("{}M", n));
|
||||
fn delete_lines(term: &mut Terminal, host: &mut TerminalHost, n: usize) {
|
||||
term.advance_bytes(CSI, host);
|
||||
term.advance_bytes(format!("{}M", n), host);
|
||||
}
|
||||
|
||||
fn cup(term: &mut Terminal, col: isize, row: isize) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(format!("{};{}H", row + 1, col + 1));
|
||||
fn cup(term: &mut Terminal, host: &mut TerminalHost, col: isize, row: isize) {
|
||||
term.advance_bytes(CSI, host);
|
||||
term.advance_bytes(format!("{};{}H", row + 1, col + 1), host);
|
||||
}
|
||||
|
||||
fn erase_in_display(term: &mut Terminal, erase: DisplayErase) {
|
||||
term.advance_bytes(CSI);
|
||||
fn erase_in_display(term: &mut Terminal, host: &mut TerminalHost, erase: DisplayErase) {
|
||||
term.advance_bytes(CSI, host);
|
||||
let num = match erase {
|
||||
DisplayErase::Below => 0,
|
||||
DisplayErase::Above => 1,
|
||||
DisplayErase::All => 2,
|
||||
DisplayErase::SavedLines => 3,
|
||||
};
|
||||
term.advance_bytes(format!("{}J", num));
|
||||
term.advance_bytes(format!("{}J", num), host);
|
||||
}
|
||||
|
||||
fn erase_in_line(term: &mut Terminal, erase: LineErase) {
|
||||
term.advance_bytes(CSI);
|
||||
fn erase_in_line(term: &mut Terminal, host: &mut TerminalHost, erase: LineErase) {
|
||||
term.advance_bytes(CSI, host);
|
||||
let num = match erase {
|
||||
LineErase::ToRight => 0,
|
||||
LineErase::ToLeft => 1,
|
||||
LineErase::All => 2,
|
||||
};
|
||||
term.advance_bytes(format!("{}K", num));
|
||||
term.advance_bytes(format!("{}K", num), host);
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@ -166,9 +198,10 @@ fn assert_visible_contents(term: &Terminal, expect_lines: &[&str]) {
|
||||
#[test]
|
||||
fn basic_output() {
|
||||
let mut term = Terminal::new(5, 10, 0);
|
||||
let mut host = TestHost::new();
|
||||
|
||||
cup(&mut term, 1, 1);
|
||||
term.advance_bytes("hello, world!");
|
||||
cup(&mut term, &mut host, 1, 1);
|
||||
term.advance_bytes("hello, world!", &mut host);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
@ -180,7 +213,7 @@ fn basic_output() {
|
||||
],
|
||||
);
|
||||
|
||||
erase_in_display(&mut term, DisplayErase::Above);
|
||||
erase_in_display(&mut term, &mut host, DisplayErase::Above);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
@ -192,8 +225,8 @@ fn basic_output() {
|
||||
],
|
||||
);
|
||||
|
||||
cup(&mut term, 2, 2);
|
||||
erase_in_line(&mut term, LineErase::ToRight);
|
||||
cup(&mut term, &mut host, 2, 2);
|
||||
erase_in_line(&mut term, &mut host, LineErase::ToRight);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
@ -205,7 +238,7 @@ fn basic_output() {
|
||||
],
|
||||
);
|
||||
|
||||
erase_in_line(&mut term, LineErase::ToLeft);
|
||||
erase_in_line(&mut term, &mut host, LineErase::ToLeft);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
@ -223,20 +256,21 @@ fn basic_output() {
|
||||
#[test]
|
||||
fn cursor_movement_damage() {
|
||||
let mut term = Terminal::new(2, 3, 0);
|
||||
let mut host = TestHost::new();
|
||||
|
||||
term.advance_bytes("fooo.");
|
||||
term.advance_bytes("fooo.", &mut host);
|
||||
assert_visible_contents(&term, &["foo", "o. "]);
|
||||
assert_cursor_pos!(&term, 2, 1);
|
||||
assert_dirty_lines!(&term, &[0, 1]);
|
||||
|
||||
cup(&mut term, 0, 1);
|
||||
cup(&mut term, &mut host, 0, 1);
|
||||
term.clean_dirty_lines();
|
||||
term.advance_bytes("\x08");
|
||||
term.advance_bytes("\x08", &mut host);
|
||||
assert_cursor_pos!(&term, 0, 1, "BS doesn't change the line");
|
||||
assert_dirty_lines!(&term, &[1]);
|
||||
term.clean_dirty_lines();
|
||||
|
||||
cup(&mut term, 0, 0);
|
||||
cup(&mut term, &mut host, 0, 0);
|
||||
assert_dirty_lines!(&term, &[0, 1], "cursor movement dirties old and new lines");
|
||||
}
|
||||
|
||||
@ -247,36 +281,37 @@ fn cursor_movement_damage() {
|
||||
#[test]
|
||||
fn test_delete_lines() {
|
||||
let mut term = Terminal::new(5, 3, 0);
|
||||
let mut host = TestHost::new();
|
||||
|
||||
term.advance_bytes("111\r\n222\r\n333\r\n444\r\n555");
|
||||
term.advance_bytes("111\r\n222\r\n333\r\n444\r\n555", &mut host);
|
||||
assert_visible_contents(&term, &["111", "222", "333", "444", "555"]);
|
||||
assert_dirty_lines!(&term, &[0, 1, 2, 3, 4]);
|
||||
cup(&mut term, 0, 1);
|
||||
cup(&mut term, &mut host, 0, 1);
|
||||
term.clean_dirty_lines();
|
||||
|
||||
assert_dirty_lines!(&term, &[]);
|
||||
delete_lines(&mut term, 2);
|
||||
delete_lines(&mut term, &mut host, 2);
|
||||
assert_visible_contents(&term, &["111", "444", "555", " ", " "]);
|
||||
assert_dirty_lines!(&term, &[1, 2, 3, 4]);
|
||||
term.clean_dirty_lines();
|
||||
|
||||
cup(&mut term, 0, 3);
|
||||
term.advance_bytes("aaa\r\nbbb");
|
||||
cup(&mut term, 0, 1);
|
||||
cup(&mut term, &mut host, 0, 3);
|
||||
term.advance_bytes("aaa\r\nbbb", &mut host);
|
||||
cup(&mut term, &mut host, 0, 1);
|
||||
term.clean_dirty_lines();
|
||||
assert_visible_contents(&term, &["111", "444", "555", "aaa", "bbb"]);
|
||||
|
||||
// test with a scroll region smaller than the screen
|
||||
set_scroll_region(&mut term, 1, 3);
|
||||
delete_lines(&mut term, 1);
|
||||
set_scroll_region(&mut term, &mut host, 1, 3);
|
||||
delete_lines(&mut term, &mut host, 1);
|
||||
|
||||
assert_visible_contents(&term, &["111", "555", "aaa", " ", "bbb"]);
|
||||
assert_dirty_lines!(&term, &[1, 2, 3]);
|
||||
|
||||
// expand the scroll region to fill the screen
|
||||
set_scroll_region(&mut term, 0, 4);
|
||||
set_scroll_region(&mut term, &mut host, 0, 4);
|
||||
term.clean_dirty_lines();
|
||||
delete_lines(&mut term, 1);
|
||||
delete_lines(&mut term, &mut host, 1);
|
||||
|
||||
assert_visible_contents(&term, &["111", "aaa", " ", "bbb", " "]);
|
||||
assert_dirty_lines!(&term, &[1, 2, 3, 4]);
|
||||
|
Loading…
Reference in New Issue
Block a user