1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-18 02:42:05 +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 termwiz;
use failure::Error;
use std::cell::Cell;
use termwiz::caps::Capabilities;
use termwiz::color::AnsiColor;
use termwiz::input::*;
@ -14,6 +17,7 @@ use termwiz::widgets::*;
#[derive(Default)]
struct MainScreen {
buf: String,
cursor: Cell<ParentRelativeCoords>,
}
impl WidgetImpl for MainScreen {
@ -45,6 +49,18 @@ impl WidgetImpl for MainScreen {
fn render_to_surface(&self, surface: &mut Surface) {
surface.add_change(Change::ClearScreen(AnsiColor::Blue.into()));
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 failure;
use std::io::{Read, Write};
use surface::{Change, Position};
use surface::{Change, CursorShape, Position};
use terminal::unix::UnixTty;
use terminfo::{capability as cap, Capability as TermInfoCapability};
@ -14,6 +14,8 @@ pub struct TerminfoRenderer {
caps: Capabilities,
current_attr: 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 {
@ -477,6 +479,39 @@ impl TerminfoRenderer {
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) => {
self.current_attr = all.clone();
}
Change::CursorColor(_color) => {}
Change::CursorShape(_shape) => {}
}
}
out.flush()?;

View File

@ -19,6 +19,24 @@ pub enum Position {
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`.
/// Changes to the active attributes (color, style), moving the cursor
/// and outputting text are examples of some of the values.
@ -52,8 +70,11 @@ pub enum Change {
ClearToEndOfScreen(ColorAttribute),
/// Move the cursor to the specified `Position`.
CursorPosition { x: Position, y: Position },
/* CursorVisibility(bool),
* ChangeScrollRegion{top: usize, bottom: usize}, */
/// Change the cursor color.
CursorColor(ColorAttribute),
/// Change the cursor shape
CursorShape(CursorShape),
/* ChangeScrollRegion{top: usize, bottom: usize}, */
}
impl Change {
@ -206,6 +227,8 @@ pub struct Surface {
ypos: usize,
seqno: SequenceNo,
changes: Vec<Change>,
cursor_shape: CursorShape,
cursor_color: ColorAttribute,
}
impl Surface {
@ -225,6 +248,10 @@ impl Surface {
(self.width, self.height)
}
pub fn cursor_position(&self) -> (usize, usize) {
(self.xpos, self.ypos)
}
/// Resize the Surface to the specified width and height.
/// 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
@ -294,6 +321,8 @@ impl Surface {
Change::ClearScreen(color) => self.clear_screen(color),
Change::ClearToEndOfLine(color) => self.clear_eol(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.
self.seqno = 0;
self.terminal.render(&changes)?;
self.terminal.flush()?;
//self.terminal.flush()?;
self.seqno = seq;
}
self.surface.flush_changes_older_than(self.seqno);

View File

@ -1,7 +1,8 @@
use color::ColorAttribute;
use input::InputEvent;
use std::cell::{Ref, RefCell, RefMut};
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
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 {
/// Called once by the widget manager to inform the widget
/// of its identifier
@ -58,12 +66,17 @@ pub trait WidgetImpl {
fn get_size_constraints(&self) -> SizeConstraints;
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
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ParentRelativeCoords {
x: usize,
y: usize,
pub x: usize,
pub y: usize,
}
impl ParentRelativeCoords {
@ -73,9 +86,10 @@ impl ParentRelativeCoords {
}
/// Relative to the top left of the screen
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ScreenRelativeCoords {
x: usize,
y: usize,
pub x: usize,
pub y: usize,
}
impl ScreenRelativeCoords {
@ -192,6 +206,25 @@ impl Widget {
pub fn add_child(&mut self, widget: &WidgetHandle) {
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 {
@ -243,5 +276,18 @@ impl Screen {
/// and then progresses up through its children.
pub fn render_to_screen(&mut self, screen: &mut Surface) {
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),
},
]);
}
}