1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-18 10:52:16 +03:00

ensure that we set the cursor attributes

Set the cursor to match the positioning info reported
by the focused widget
This commit is contained in:
Wez Furlong 2018-07-24 16:47:41 -07:00
parent 837cfae566
commit b3346b9a43
6 changed files with 137 additions and 9 deletions

View File

@ -1,7 +1,10 @@
//! This example shows how to make a basic widget that accumulates
//! text input and renders it to the screen
extern crate failure; extern crate failure;
extern crate termwiz; extern crate termwiz;
use failure::Error; use failure::Error;
use std::cell::Cell;
use termwiz::caps::Capabilities; use termwiz::caps::Capabilities;
use termwiz::color::AnsiColor; use termwiz::color::AnsiColor;
use termwiz::input::*; use termwiz::input::*;
@ -14,6 +17,7 @@ use termwiz::widgets::*;
#[derive(Default)] #[derive(Default)]
struct MainScreen { struct MainScreen {
buf: String, buf: String,
cursor: Cell<ParentRelativeCoords>,
} }
impl WidgetImpl for MainScreen { impl WidgetImpl for MainScreen {
@ -45,6 +49,18 @@ impl WidgetImpl for MainScreen {
fn render_to_surface(&self, surface: &mut Surface) { fn render_to_surface(&self, surface: &mut Surface) {
surface.add_change(Change::ClearScreen(AnsiColor::Blue.into())); surface.add_change(Change::ClearScreen(AnsiColor::Blue.into()));
surface.add_change(self.buf.clone()); surface.add_change(self.buf.clone());
// Allow the surface rendering code to figure out where the
// cursor ends up, then stash a copy of that information for
// later retrieval by get_cursor_shape_and_position().
let (x, y) = surface.cursor_position();
self.cursor.set(ParentRelativeCoords::new(x, y));
}
fn get_cursor_shape_and_position(&self) -> CursorShapeAndPosition {
CursorShapeAndPosition {
coords: self.cursor.get(),
..Default::default()
}
} }
} }

View File

@ -6,7 +6,7 @@ use escape::csi::{Cursor, Edit, EraseInDisplay, EraseInLine, Sgr, CSI};
use escape::osc::OperatingSystemCommand; use escape::osc::OperatingSystemCommand;
use failure; use failure;
use std::io::{Read, Write}; use std::io::{Read, Write};
use surface::{Change, Position}; use surface::{Change, CursorShape, Position};
use terminal::unix::UnixTty; use terminal::unix::UnixTty;
use terminfo::{capability as cap, Capability as TermInfoCapability}; use terminfo::{capability as cap, Capability as TermInfoCapability};
@ -14,6 +14,8 @@ pub struct TerminfoRenderer {
caps: Capabilities, caps: Capabilities,
current_attr: CellAttributes, current_attr: CellAttributes,
pending_attr: Option<CellAttributes>, pending_attr: Option<CellAttributes>,
/* TODO: we should record cursor position, shape and color here
* so that we can optimize updating them on screen. */
} }
impl TerminfoRenderer { impl TerminfoRenderer {
@ -477,6 +479,39 @@ impl TerminfoRenderer {
change change
); );
} }
Change::CursorColor(_color) => {
// TODO: this isn't spec'd by terminfo, but some terminals
// support it. Add this to capabilities?
}
Change::CursorShape(shape) => match shape {
CursorShape::Default => {
if let Some(reset) = self.get_capability::<cap::ResetCursorStyle>() {
reset.expand().to(out.by_ref())?;
}
}
CursorShape::Hidden => {
if let Some(hide) = self.get_capability::<cap::CursorInvisible>() {
hide.expand().to(out.by_ref())?;
}
}
_ => {
if let Some(show) = self.get_capability::<cap::CursorVisible>() {
show.expand().to(out.by_ref())?;
}
let param = match shape {
CursorShape::Default | CursorShape::Hidden => unreachable!(),
CursorShape::BlinkingBlock => 1,
CursorShape::SteadyBlock => 2,
CursorShape::BlinkingUnderline => 3,
CursorShape::SteadyUnderline => 4,
CursorShape::BlinkingBar => 6,
CursorShape::SteadyBar => 7,
};
if let Some(set) = self.get_capability::<cap::SetCursorStyle>() {
set.expand().kind(param).to(out.by_ref())?;
}
}
},
} }
} }

View File

@ -260,6 +260,8 @@ impl WindowsConsoleRenderer {
Change::AllAttributes(all) => { Change::AllAttributes(all) => {
self.current_attr = all.clone(); self.current_attr = all.clone();
} }
Change::CursorColor(_color) => {}
Change::CursorShape(_shape) => {}
} }
} }
out.flush()?; out.flush()?;

View File

@ -19,6 +19,24 @@ pub enum Position {
EndRelative(usize), EndRelative(usize),
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorShape {
Hidden,
Default,
BlinkingBlock,
SteadyBlock,
BlinkingUnderline,
SteadyUnderline,
BlinkingBar,
SteadyBar,
}
impl Default for CursorShape {
fn default() -> CursorShape {
CursorShape::Default
}
}
/// `Change` describes an update operation to be applied to a `Surface`. /// `Change` describes an update operation to be applied to a `Surface`.
/// Changes to the active attributes (color, style), moving the cursor /// Changes to the active attributes (color, style), moving the cursor
/// and outputting text are examples of some of the values. /// and outputting text are examples of some of the values.
@ -52,8 +70,11 @@ pub enum Change {
ClearToEndOfScreen(ColorAttribute), ClearToEndOfScreen(ColorAttribute),
/// Move the cursor to the specified `Position`. /// Move the cursor to the specified `Position`.
CursorPosition { x: Position, y: Position }, CursorPosition { x: Position, y: Position },
/* CursorVisibility(bool), /// Change the cursor color.
* ChangeScrollRegion{top: usize, bottom: usize}, */ CursorColor(ColorAttribute),
/// Change the cursor shape
CursorShape(CursorShape),
/* ChangeScrollRegion{top: usize, bottom: usize}, */
} }
impl Change { impl Change {
@ -206,6 +227,8 @@ pub struct Surface {
ypos: usize, ypos: usize,
seqno: SequenceNo, seqno: SequenceNo,
changes: Vec<Change>, changes: Vec<Change>,
cursor_shape: CursorShape,
cursor_color: ColorAttribute,
} }
impl Surface { impl Surface {
@ -225,6 +248,10 @@ impl Surface {
(self.width, self.height) (self.width, self.height)
} }
pub fn cursor_position(&self) -> (usize, usize) {
(self.xpos, self.ypos)
}
/// Resize the Surface to the specified width and height. /// Resize the Surface to the specified width and height.
/// If the width and/or height are smaller than previously, the rows and/or /// If the width and/or height are smaller than previously, the rows and/or
/// columns are truncated. If the width and/or height are larger than /// columns are truncated. If the width and/or height are larger than
@ -294,6 +321,8 @@ impl Surface {
Change::ClearScreen(color) => self.clear_screen(color), Change::ClearScreen(color) => self.clear_screen(color),
Change::ClearToEndOfLine(color) => self.clear_eol(color), Change::ClearToEndOfLine(color) => self.clear_eol(color),
Change::ClearToEndOfScreen(color) => self.clear_eos(color), Change::ClearToEndOfScreen(color) => self.clear_eos(color),
Change::CursorColor(color) => self.cursor_color = color.clone(),
Change::CursorShape(shape) => self.cursor_shape = shape.clone(),
} }
} }

View File

@ -55,7 +55,7 @@ impl<T: Terminal> BufferedTerminal<T> {
// renders all. // renders all.
self.seqno = 0; self.seqno = 0;
self.terminal.render(&changes)?; self.terminal.render(&changes)?;
self.terminal.flush()?; //self.terminal.flush()?;
self.seqno = seq; self.seqno = seq;
} }
self.surface.flush_changes_older_than(self.seqno); self.surface.flush_changes_older_than(self.seqno);

View File

@ -1,7 +1,8 @@
use color::ColorAttribute;
use input::InputEvent; use input::InputEvent;
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use surface::{SequenceNo, Surface}; use surface::{Change, CursorShape, Position, SequenceNo, Surface};
/// Describes an event that may need to be processed by the widget /// Describes an event that may need to be processed by the widget
pub enum WidgetEvent { pub enum WidgetEvent {
@ -46,6 +47,13 @@ impl SizeConstraints {
} }
} }
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CursorShapeAndPosition {
pub shape: CursorShape,
pub coords: ParentRelativeCoords,
pub color: ColorAttribute,
}
pub trait WidgetImpl { pub trait WidgetImpl {
/// Called once by the widget manager to inform the widget /// Called once by the widget manager to inform the widget
/// of its identifier /// of its identifier
@ -58,12 +66,17 @@ pub trait WidgetImpl {
fn get_size_constraints(&self) -> SizeConstraints; fn get_size_constraints(&self) -> SizeConstraints;
fn render_to_surface(&self, surface: &mut Surface); fn render_to_surface(&self, surface: &mut Surface);
/// Called for the focused widget to determine how to render
/// the cursor.
fn get_cursor_shape_and_position(&self) -> CursorShapeAndPosition;
} }
/// Relative to the top left of the parent container /// Relative to the top left of the parent container
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ParentRelativeCoords { pub struct ParentRelativeCoords {
x: usize, pub x: usize,
y: usize, pub y: usize,
} }
impl ParentRelativeCoords { impl ParentRelativeCoords {
@ -73,9 +86,10 @@ impl ParentRelativeCoords {
} }
/// Relative to the top left of the screen /// Relative to the top left of the screen
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ScreenRelativeCoords { pub struct ScreenRelativeCoords {
x: usize, pub x: usize,
y: usize, pub y: usize,
} }
impl ScreenRelativeCoords { impl ScreenRelativeCoords {
@ -192,6 +206,25 @@ impl Widget {
pub fn add_child(&mut self, widget: &WidgetHandle) { pub fn add_child(&mut self, widget: &WidgetHandle) {
self.children.push(widget.clone()); self.children.push(widget.clone());
} }
pub fn to_screen_coords(&self, coords: &ParentRelativeCoords) -> ScreenRelativeCoords {
let mut x = coords.x;
let mut y = coords.y;
let mut widget = self.parent();
loop {
let parent = match widget {
Some(parent) => {
let p = parent.borrow();
x += p.coordinates.x;
y += p.coordinates.y;
p.parent()
}
None => break,
};
widget = parent;
}
ScreenRelativeCoords { x, y }
}
} }
pub struct Screen { pub struct Screen {
@ -243,5 +276,18 @@ impl Screen {
/// and then progresses up through its children. /// and then progresses up through its children.
pub fn render_to_screen(&mut self, screen: &mut Surface) { pub fn render_to_screen(&mut self, screen: &mut Surface) {
self.root_widget.borrow_mut().render_to_screen(screen); self.root_widget.borrow_mut().render_to_screen(screen);
let focused = self.focused_widget.borrow();
let cursor = focused.inner.get_cursor_shape_and_position();
let coords = focused.to_screen_coords(&cursor.coords);
screen.add_changes(vec![
Change::CursorShape(cursor.shape),
Change::CursorColor(cursor.color),
Change::CursorPosition {
x: Position::Absolute(coords.x),
y: Position::Absolute(coords.y),
},
]);
} }
} }