mirror of
https://github.com/wez/wezterm.git
synced 2024-11-22 22:42:48 +03:00
We're now able to run and render top
This commit is contained in:
parent
e63f003ad0
commit
a11a34b031
@ -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)
|
||||
}
|
||||
|
64
src/main.rs
64
src/main.rs
@ -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,
|
||||
|
20
src/pty.rs
20
src/pty.rs
@ -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))
|
||||
}
|
||||
|
||||
|
102
src/term/mod.rs
102
src/term/mod.rs
@ -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) {}
|
||||
|
Loading…
Reference in New Issue
Block a user