1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-26 16:34:23 +03:00

We're now able to run and render top

This commit is contained in:
Wez Furlong 2018-01-27 11:15:53 -08:00
parent e63f003ad0
commit a11a34b031
4 changed files with 165 additions and 26 deletions

View File

@ -66,7 +66,10 @@ impl Face {
unsafe {
let res = FT_Load_Glyph(self.face, glyph_index, load_flags);
if res.succeeded() {
FT_Render_Glyph((*self.face).glyph, render_mode);
let render = FT_Render_Glyph((*self.face).glyph, render_mode);
if !render.succeeded() {
bail!("FT_Render_Glyph failed: {:?}", render);
}
}
ft_result(res, &*(*self.face).glyph)
}

View File

@ -109,6 +109,12 @@ impl<'a> TerminalWindow<'a> {
self.buffer_image = buffer;
self.width = width;
self.height = height;
let rows = height / self.cell_height as u16;
let cols = width / self.cell_width as u16;
self.pty.resize(rows, cols, width, height);
self.terminal.resize(rows as usize, cols as usize);
self.need_paint = true;
Ok(true)
} else {
@ -141,7 +147,6 @@ impl<'a> TerminalWindow<'a> {
}
fn paint(&mut self) -> Result<(), Error> {
debug!("paint");
self.need_paint = false;
let palette = term::color::ColorPalette::default();
@ -170,13 +175,25 @@ impl<'a> TerminalWindow<'a> {
let attrs = &line.cells[cell_idx].attrs;
let (fg_color, bg_color) = if attrs.reverse() {
(
palette.resolve(&attrs.background),
palette.resolve(&attrs.foreground),
)
} else {
(
palette.resolve(&attrs.foreground),
palette.resolve(&attrs.background),
)
};
// Render the cell background color
self.buffer_image.clear_rect(
x,
y - cell_height as isize,
info.num_cells as usize * self.cell_width as usize,
cell_height,
palette.resolve(&attrs.background).into(),
bg_color.into(),
);
let scale = if (info.x_advance / info.num_cells as f64).floor() > self.cell_width {
@ -267,7 +284,7 @@ impl<'a> TerminalWindow<'a> {
let operator = if has_color {
xgfx::Operator::Over
} else {
xgfx::Operator::MultiplyThenOver(palette.resolve(&attrs.foreground).into())
xgfx::Operator::MultiplyThenOver(fg_color.into())
};
self.buffer_image.draw_image(
x + x_offset as isize + bearing_x,
@ -282,17 +299,35 @@ impl<'a> TerminalWindow<'a> {
}
}
// FIXME: we have to push the render to the server in case it
// was the result of output from the process on the pty. It would
// be nice to make this paint function only re-render the changed
// portions and send only those to the X server here.
self.window_context.put_image(0, 0, &self.buffer_image);
Ok(())
}
fn handle_pty_readable_event(&mut self) {
println!("readable, doing read!");
let mut buf = [0; 256];
const kBufSize: usize = 8192;
let mut buf = [0; kBufSize];
match self.pty.read(&mut buf) {
Ok(size) => println!("[ls] {}", std::str::from_utf8(&buf[0..size]).unwrap()),
Err(err) => {
eprintln!("[ls:err] {:?}", err);
loop {
match self.pty.read(&mut buf) {
Ok(size) => {
self.terminal.advance_bytes(&buf[0..size]);
self.need_paint = true;
if size < kBufSize {
// If we had a short read then there is no more
// data to read right now; we'll get called again
// when mio says that we're ready
break;
}
}
Err(err) => {
eprintln!("error reading from pty: {:?}", err);
break;
}
}
}
}
@ -355,14 +390,15 @@ fn run() -> Result<(), Error> {
let initial_pixel_width = initial_cols * cell_width.ceil() as u16;
let initial_pixel_height = initial_rows * cell_height.ceil() as u16;
let (mut master, slave) = pty::openpty(
let (master, slave) = pty::openpty(
initial_rows,
initial_cols,
initial_pixel_width,
initial_pixel_height,
)?;
let cmd = Command::new("ls");
let mut cmd = Command::new("top");
// cmd.arg("-l");
let child = slave.spawn_command(cmd)?;
eprintln!("spawned: {:?}", child);
@ -381,9 +417,9 @@ fn run() -> Result<(), Error> {
PollOpt::edge(),
)?;
let mut terminal = term::Terminal::new(initial_rows as usize, initial_cols as usize, 3000);
let message = "x_advance != \x1b[38;2;1;0;125;145;mfoo->bar(); ❤ 😍🤢\n\x1b[91;mw00t\n\x1b[37;104;m bleet\x1b[0;m.";
terminal.advance_bytes(message);
let terminal = term::Terminal::new(initial_rows as usize, initial_cols as usize, 3000);
// let message = "x_advance != \x1b[38;2;1;0;125;145;mfoo->bar(); ❤ 😍🤢\n\x1b[91;mw00t\n\x1b[37;104;m bleet\x1b[0;m.";
// terminal.advance_bytes(message);
let mut window = TerminalWindow::new(
&conn,

View File

@ -78,6 +78,24 @@ fn dup(fd: RawFd) -> Result<RawFd, Error> {
}
}
fn set_nonblocking(fd: RawFd) -> Result<(), Error> {
let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
if flags == -1 {
bail!(
"fcntl to read flags failed: {:?}",
io::Error::last_os_error()
);
}
let result = unsafe { libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK) };
if result == -1 {
bail!(
"fcntl to set NONBLOCK failed: {:?}",
io::Error::last_os_error()
);
}
Ok(())
}
/// Create a new Pty instance with the window size set to the specified
/// dimensions. Returns a (master, slave) Pty pair. The master side
/// is used to drive the slave side.
@ -114,6 +132,8 @@ pub fn openpty(
cloexec(master.fd)?;
cloexec(slave.fd)?;
set_nonblocking(master.fd)?;
Ok((master, slave))
}

View File

@ -109,7 +109,7 @@ impl Default for CellAttributes {
}
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Cell {
chars: [u8; 8],
pub attrs: CellAttributes,
@ -245,7 +245,7 @@ impl Screen {
let line_idx = (self.lines.len() - self.physical_rows) + y;
// TODO: if the line isn't wide enough, we should pad it out with
// the default attributes
println!(
debug!(
"set_cell x,y {},{}, line_idx = {} {} {:?}",
x,
y,
@ -255,6 +255,19 @@ impl Screen {
);
self.lines[line_idx].cells[x] = Cell::from_char(c, attr);
}
pub fn clear_line(&mut self, y: usize, cols: std::ops::Range<usize>) {
let blank = Cell::from_char(' ', &CellAttributes::default());
let line_idx = (self.lines.len() - self.physical_rows) + y;
let line = &mut self.lines[line_idx];
let max_col = line.cells.len();
for x in cols {
if x >= max_col {
break;
}
line.cells[x] = blank;
}
}
}
pub struct TerminalState {
@ -354,6 +367,12 @@ impl Terminal {
self.state.state_changed = false;
}
pub fn resize(&mut self, physical_rows: usize, physical_cols: usize) {
self.state.screen.resize(physical_rows, physical_cols);
self.state.alt_screen.resize(physical_rows, physical_cols);
}
/// Returns the width of the screen and a slice over the visible rows
/// TODO: should allow an arbitrary view for scrollback
pub fn visible_cells(&self) -> (usize, &[Line]) {
@ -369,6 +388,7 @@ impl Terminal {
}
}
#[derive(Debug)]
enum CSIAction {
SetPen(CellAttributes),
SetForegroundColor(color::ColorAttribute),
@ -523,10 +543,13 @@ impl vte::Perform for TerminalState {
fn execute(&mut self, byte: u8) {
match byte {
b'\n' => {
self.cursor_x = 0;
self.cursor_y += 1;
self.state_changed = true;
}
b'\r' => {
self.cursor_x = 0;
self.state_changed = true;
}
_ => println!("unhandled vte execute {}", byte),
}
}
@ -535,16 +558,15 @@ impl vte::Perform for TerminalState {
fn unhook(&mut self) {}
fn osc_dispatch(&mut self, _: &[&[u8]]) {}
fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: char) {
println!(
"CSI: params {:?} intermediates {:?} ignore={} byte={}",
params,
intermediates,
ignore,
byte
);
match byte {
'm' => {
let mut params = params;
if params.len() == 0 {
// Empty parameter list means to reset the attributes to default
self.pen = CellAttributes::default();
}
while params.len() > 0 {
match CSIAction::parse_sgr(params) {
Some((CSIAction::SetPen(pen), remainder)) => {
@ -594,7 +616,65 @@ impl vte::Perform for TerminalState {
}
}
}
_ => {}
'H' => {
// Cursor Position (CUP)
if params.len() == 2 {
// coordinates are 1-based; convert to 0-based
self.cursor_y = (params[0] - 1) as usize;
self.cursor_x = (params[1] - 1) as usize;
} else {
// no parameters -> home the cursor
self.cursor_x = 0;
self.cursor_y = 0;
}
}
'K' => {
// Erase in line (EL)
#[derive(Debug)]
enum Erase {
ToRight,
ToLeft,
All,
Unknown,
}
let what = if params.len() == 0 {
Erase::ToRight
} else {
match params[0] {
0 => Erase::ToRight,
1 => Erase::ToLeft,
2 => Erase::All,
_ => Erase::Unknown,
}
};
let cx = self.cursor_x;
let cy = self.cursor_y;
let mut screen = self.screen_mut();
let cols = screen.physical_cols;
match what {
Erase::ToRight => {
screen.clear_line(cy, cx..cols);
}
Erase::ToLeft => {
screen.clear_line(cy, 0..cx);
}
Erase::All => {
screen.clear_line(cy, 0..cols);
}
Erase::Unknown => {}
}
}
_ => {
println!(
"CSI: unhandled params {:?} intermediates {:?} ignore={} byte={}",
params,
intermediates,
ignore,
byte
);
}
}
}
fn esc_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: u8) {}