1
1
mirror of https://github.com/wez/wezterm.git synced 2025-01-03 03:04:04 +03:00

termwiz: Remove anyhow::Result from public API

It's been replaced with an opaque termwiz error type instead.

This is a bit of a more conservative approach than that in (refs: #407)
and has less of an impact on the surrounding code, which appeals to
me from a maintenance perspective.

refs: #406
refs: #407
This commit is contained in:
Wez Furlong 2021-01-08 00:21:54 -08:00
parent 713da95a02
commit 5d360ae365
28 changed files with 392 additions and 223 deletions

1
Cargo.lock generated
View File

@ -3683,6 +3683,7 @@ dependencies = [
"signal-hook",
"terminfo",
"termios 0.3.3",
"thiserror",
"unicode-segmentation",
"unicode-width",
"varbincode",

View File

@ -29,6 +29,7 @@ use termwiz::render::terminfo::TerminfoRenderer;
use termwiz::surface::Change;
use termwiz::surface::Line;
use termwiz::terminal::{ScreenSize, TerminalWaker};
use termwiz::Context;
use url::Url;
use wezterm_term::color::ColorPalette;
use wezterm_term::{KeyCode, KeyModifiers, MouseEvent, StableRowIndex};
@ -269,13 +270,13 @@ impl std::io::Write for TermWizTerminalRenderTty {
}
impl termwiz::render::RenderTty for TermWizTerminalRenderTty {
fn get_size_in_cells(&mut self) -> anyhow::Result<(usize, usize)> {
fn get_size_in_cells(&mut self) -> termwiz::Result<(usize, usize)> {
Ok((self.screen_size.cols, self.screen_size.rows))
}
}
impl TermWizTerminal {
fn do_input_poll(&mut self, wait: Option<Duration>) -> anyhow::Result<Option<InputEvent>> {
fn do_input_poll(&mut self, wait: Option<Duration>) -> termwiz::Result<Option<InputEvent>> {
if let Some(timeout) = wait {
match self.input_rx.recv_timeout(timeout) {
Ok(input) => Ok(Some(input)),
@ -283,19 +284,19 @@ impl TermWizTerminal {
if err.is_timeout() {
Ok(None)
} else {
Err(err.into())
Err(err).context("receive from channel")
}
}
}
} else {
let input = self.input_rx.recv()?;
let input = self.input_rx.recv().context("receive from channel")?;
Ok(Some(input))
}
}
}
impl termwiz::terminal::Terminal for TermWizTerminal {
fn set_raw_mode(&mut self) -> anyhow::Result<()> {
fn set_raw_mode(&mut self) -> termwiz::Result<()> {
use termwiz::escape::csi::{DecPrivateMode, DecPrivateModeCode, Mode, CSI};
macro_rules! decset {
@ -318,37 +319,37 @@ impl termwiz::terminal::Terminal for TermWizTerminal {
Ok(())
}
fn set_cooked_mode(&mut self) -> anyhow::Result<()> {
fn set_cooked_mode(&mut self) -> termwiz::Result<()> {
Ok(())
}
fn enter_alternate_screen(&mut self) -> anyhow::Result<()> {
bail!("TermWizTerminalPane has no alt screen");
fn enter_alternate_screen(&mut self) -> termwiz::Result<()> {
termwiz::bail!("TermWizTerminalPane has no alt screen");
}
fn exit_alternate_screen(&mut self) -> anyhow::Result<()> {
bail!("TermWizTerminalPane has no alt screen");
fn exit_alternate_screen(&mut self) -> termwiz::Result<()> {
termwiz::bail!("TermWizTerminalPane has no alt screen");
}
fn get_screen_size(&mut self) -> anyhow::Result<ScreenSize> {
fn get_screen_size(&mut self) -> termwiz::Result<ScreenSize> {
Ok(self.render_tx.screen_size)
}
fn set_screen_size(&mut self, _size: ScreenSize) -> anyhow::Result<()> {
bail!("TermWizTerminalPane cannot set screen size");
fn set_screen_size(&mut self, _size: ScreenSize) -> termwiz::Result<()> {
termwiz::bail!("TermWizTerminalPane cannot set screen size");
}
fn render(&mut self, changes: &[Change]) -> anyhow::Result<()> {
fn render(&mut self, changes: &[Change]) -> termwiz::Result<()> {
self.renderer.render_to(changes, &mut self.render_tx)?;
Ok(())
}
fn flush(&mut self) -> anyhow::Result<()> {
fn flush(&mut self) -> termwiz::Result<()> {
self.render_tx.render_tx.flush()?;
Ok(())
}
fn poll_input(&mut self, wait: Option<Duration>) -> anyhow::Result<Option<InputEvent>> {
fn poll_input(&mut self, wait: Option<Duration>) -> termwiz::Result<Option<InputEvent>> {
self.do_input_poll(wait).map(|i| {
if let Some(InputEvent::Resized { cols, rows }) = i.as_ref() {
self.render_tx.screen_size.cols = *cols;

View File

@ -27,6 +27,7 @@ regex = "1"
semver = "0.11"
serde = {version="1.0", features = ["rc", "derive"], optional=true}
terminfo = "0.7"
thiserror = "1.0"
unicode-segmentation = "1.7"
unicode-width = "0.1"
xi-unicode = "0.3"

View File

@ -2,13 +2,13 @@
//! up changes and then flush them. `BufferedTerminal` enables
//! optimizing the output sequence to update the screen, which is
//! important on links with poor connectivity.
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::cell::AttributeChange;
use termwiz::color::AnsiColor;
use termwiz::surface::Change;
use termwiz::terminal::buffered::BufferedTerminal;
use termwiz::terminal::{new_terminal, Terminal};
use termwiz::Error;
fn main() -> Result<(), Error> {
let caps = Capabilities::new_from_env()?;

View File

@ -1,4 +1,3 @@
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::cell::AttributeChange;
use termwiz::color::AnsiColor;
@ -6,6 +5,7 @@ use termwiz::input::{InputEvent, KeyCode, KeyEvent};
use termwiz::surface::{Change, Position, Surface};
use termwiz::terminal::buffered::BufferedTerminal;
use termwiz::terminal::{new_terminal, Terminal};
use termwiz::Error;
fn main() -> Result<(), Error> {
let caps = Capabilities::new_from_env()?;

View File

@ -1,7 +1,7 @@
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::input::{InputEvent, KeyCode, KeyEvent, Modifiers};
use termwiz::terminal::{new_terminal, Terminal};
use termwiz::Error;
const CTRL_C: KeyEvent = KeyEvent {
key: KeyCode::Char('C'),

View File

@ -90,7 +90,7 @@ fn word_at_cursor(line: &str, cursor_position: usize) -> Option<(std::ops::Range
}
}
fn main() -> anyhow::Result<()> {
fn main() -> termwiz::Result<()> {
println!("Type `exit` to quit this example, or start a word with `h` and press Tab.");
let mut terminal = line_editor_terminal()?;
let mut editor = LineEditor::new(&mut terminal);

View File

@ -5,12 +5,12 @@
//! the `buffered_terminal.rs` example demonstrates a simple
//! way to enable optimizations.
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::cell::AttributeChange;
use termwiz::color::AnsiColor;
use termwiz::surface::Change;
use termwiz::terminal::{new_terminal, Terminal};
use termwiz::Error;
fn main() -> Result<(), Error> {
let caps = Capabilities::new_from_env()?;

View File

@ -1,7 +1,6 @@
//! This example shows how to make a basic widget that accumulates
//! text input and renders it to the screen
#![allow(unused)]
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::cell::AttributeChange;
use termwiz::color::{AnsiColor, ColorAttribute, RgbColor};
@ -11,6 +10,7 @@ use termwiz::terminal::buffered::BufferedTerminal;
use termwiz::terminal::{new_terminal, Terminal};
#[cfg(feature = "widgets")]
use termwiz::widgets::*;
use termwiz::Error;
/// This is a widget for our application
struct MainScreen<'a> {

View File

@ -1,7 +1,6 @@
//! This example shows how to make an app that uses parent/child widgets
#[cfg(feature = "widgets")]
mod inner {
use anyhow::Error;
use termwiz::caps::Capabilities;
use termwiz::cell::AttributeChange;
use termwiz::color::{AnsiColor, ColorAttribute, RgbColor};
@ -11,6 +10,7 @@ mod inner {
use termwiz::terminal::{new_terminal, Terminal};
use termwiz::widgets::layout::{ChildOrientation, VerticalAlignment};
use termwiz::widgets::*;
use termwiz::Error;
/// This is the main container widget for the app
struct MainScreen {}
@ -202,12 +202,12 @@ mod inner {
#[cfg(not(feature = "widgets"))]
mod inner {
pub fn run() -> anyhow::Result<()> {
pub fn run() -> termwiz::Result<()> {
println!("recompile with --features widgets");
Ok(())
}
}
fn main() -> anyhow::Result<()> {
fn main() -> termwiz::Result<()> {
inner::run()
}

View File

@ -54,8 +54,7 @@
//! implements some heuristics (a fancy word for guessing) to compute
//! the terminal capabilities, but also offers a `ProbeHints`
//! that can be used by the embedding application to override those choices.
use crate::builder;
use anyhow::Error;
use crate::{builder, Result};
use semver::Version;
use std::env::var;
use terminfo::{self, capability as cap};
@ -163,7 +162,7 @@ impl Capabilities {
/// Capability object holding the outcome.
/// This function inspects the environment variables to build
/// up configuration hints.
pub fn new_from_env() -> Result<Self, Error> {
pub fn new_from_env() -> Result<Self> {
Self::new_with_hints(ProbeHints::new_from_env())
}
@ -184,7 +183,7 @@ impl Capabilities {
}
/// Build a `Capabilities` object based on the provided `ProbeHints` object.
pub fn new_with_hints(hints: ProbeHints) -> Result<Self, Error> {
pub fn new_with_hints(hints: ProbeHints) -> Result<Self> {
let color_level = hints.color_level.unwrap_or_else(|| {
// If set, COLORTERM overrides any other source of information
match hints.colorterm.as_ref().map(String::as_ref) {

180
termwiz/src/error.rs Normal file
View File

@ -0,0 +1,180 @@
use std::fmt::Display;
use thiserror::*;
/// The termwiz Error type encapsulates a range of internal
/// errors in an opaque manner. You can use the `source`
/// method to reach the underlying errors if
/// necessary, but it is not expected that most code will
/// need to do so. Please file an issue if you've got a
/// usecase for this!
#[derive(Error, Debug)]
#[error(transparent)]
pub struct Error(pub(crate) InternalError);
/// A Result whose error type is a termwiz Error
pub type Result<T> = std::result::Result<T, Error>;
impl<E> From<E> for Error
where
E: Into<InternalError>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
/// This enum encapsulates the various errors that can be
/// mapped into the termwiz Error type.
/// The intent is that this is effectively private to termwiz
/// itself, but since Rust doesn't allow enums with private
/// variants, we're dancing around with a newtype of an enum
/// and hiding it from the docs.
#[derive(Error, Debug)]
#[non_exhaustive]
#[doc(hidden)]
pub enum InternalError {
#[error(transparent)]
Fmt(#[from] std::fmt::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Regex(#[from] regex::Error),
#[error(transparent)]
FromUtf8(#[from] std::string::FromUtf8Error),
#[error(transparent)]
Utf8(#[from] std::str::Utf8Error),
#[error(transparent)]
Base64(#[from] base64::DecodeError),
#[error(transparent)]
ParseFloat(#[from] std::num::ParseFloatError),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[error(transparent)]
FloatIsNan(#[from] ordered_float::FloatIsNan),
#[error("{0}")]
StringErr(#[from] StringWrap),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
#[error(transparent)]
Terminfo(#[from] terminfo::Error),
#[error("{}", .context)]
Context {
context: String,
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
}
impl From<String> for InternalError {
fn from(s: String) -> Self {
InternalError::StringErr(StringWrap(s))
}
}
#[derive(Error, Debug)]
#[doc(hidden)]
#[error("{0}")]
pub struct StringWrap(pub String);
#[macro_export]
macro_rules! format_err {
($msg:literal $(,)?) => {
return $crate::error::Error::from($crate::error::StringWrap($msg.to_string()))
};
($err:expr $(,)?) => {
return $crate::error::Error::from($crate::error::StringWrap(format!($err)))
};
($fmt:expr, $($arg:tt)*) => {
return $crate::error::Error::from($crate::error::StringWrap(format!($fmt, $($arg)*)))
};
}
#[macro_export]
macro_rules! bail {
($msg:literal $(,)?) => {
return Err($crate::error::StringWrap($msg.to_string()).into())
};
($err:expr $(,)?) => {
return Err($crate::error::StringWrap(format!($err)).into())
};
($fmt:expr, $($arg:tt)*) => {
return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into())
};
}
#[macro_export]
macro_rules! ensure {
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
return Err($crate::error::StringWrap(format!($msg)).into());
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return Err($crate::error::StringWrap(format!($err)).into());
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into());
}
};
}
/// This trait allows extending the Result type so that it can create a
/// `termwiz::Error` that wraps an underlying other error and provide
/// additional context on that error.
pub trait Context<T, E> {
/// Wrap the error value with additional context.
fn context<C>(self, context: C) -> Result<T>
where
C: Display + Send + Sync + 'static;
/// Wrap the error value with additional context that is evaluated lazily
/// only once an error does occur.
fn with_context<C, F>(self, f: F) -> Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
}
impl<T, E> Context<T, E> for std::result::Result<T, E>
where
E: std::error::Error + Send + Sync + 'static,
{
fn context<C>(self, context: C) -> Result<T>
where
C: Display + Send + Sync + 'static,
{
self.map_err(|error| {
Error(InternalError::Context {
context: context.to_string(),
source: Box::new(error),
})
})
}
fn with_context<C, F>(self, context: F) -> Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.map_err(|error| {
Error(InternalError::Context {
context: context().to_string(),
source: Box::new(error),
})
})
}
}

View File

@ -1,13 +1,13 @@
use crate::color::RgbColor;
pub use crate::hyperlink::Hyperlink;
use anyhow::{anyhow, bail, ensure};
use crate::{bail, ensure, Result};
use base64;
use bitflags::bitflags;
use num_derive::*;
use num_traits::FromPrimitive;
use ordered_float::NotNan;
use std::collections::HashMap;
use std::fmt::{Display, Error as FmtError, Formatter};
use std::fmt::{Display, Error as FmtError, Formatter, Result as FmtResult};
use std::str;
#[derive(Debug, Clone, PartialEq, Eq)]
@ -17,7 +17,7 @@ pub enum ColorOrQuery {
}
impl Display for ColorOrQuery {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self {
ColorOrQuery::Query => write!(f, "?"),
ColorOrQuery::Color(c) => write!(f, "{}", c.to_x11_16bit_rgb_string()),
@ -89,7 +89,7 @@ pub struct Selection :u16{
}
impl Selection {
fn try_parse(buf: &[u8]) -> anyhow::Result<Selection> {
fn try_parse(buf: &[u8]) -> Result<Selection> {
if buf == b"" {
Ok(Selection::SELECT | Selection::CUT0)
} else {
@ -118,7 +118,7 @@ impl Selection {
}
impl Display for Selection {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
macro_rules! item {
($variant:ident, $s:expr) => {
if (*self & Selection::$variant) != Selection::NONE {
@ -160,7 +160,7 @@ impl OperatingSystemCommand {
})
}
fn parse_selection(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse_selection(osc: &[&[u8]]) -> Result<Self> {
if osc.len() == 2 {
Selection::try_parse(osc[1]).map(OperatingSystemCommand::ClearSelection)
} else if osc.len() == 3 && osc[2] == b"?" {
@ -175,7 +175,7 @@ impl OperatingSystemCommand {
}
}
fn parse_reset_colors(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse_reset_colors(osc: &[&[u8]]) -> Result<Self> {
let mut colors = vec![];
let mut iter = osc.iter();
iter.next(); // skip the command word that we already know is present
@ -191,7 +191,7 @@ impl OperatingSystemCommand {
Ok(OperatingSystemCommand::ResetColors(colors))
}
fn parse_change_color_number(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse_change_color_number(osc: &[&[u8]]) -> Result<Self> {
let mut pairs = vec![];
let mut iter = osc.iter();
iter.next(); // skip the command word that we already know is present
@ -204,7 +204,7 @@ impl OperatingSystemCommand {
} else {
ColorOrQuery::Color(
RgbColor::from_named_or_rgb_string(spec)
.ok_or_else(|| anyhow!("invalid color spec {:?}", spec))?,
.ok_or_else(|| format!("invalid color spec {:?}", spec))?,
)
};
@ -217,16 +217,16 @@ impl OperatingSystemCommand {
Ok(OperatingSystemCommand::ChangeColorNumber(pairs))
}
fn parse_reset_dynamic_color_number(idx: u8) -> anyhow::Result<Self> {
fn parse_reset_dynamic_color_number(idx: u8) -> Result<Self> {
let which_color: DynamicColorNumber = FromPrimitive::from_u8(idx)
.ok_or_else(|| anyhow!("osc code is not a valid DynamicColorNumber!?"))?;
.ok_or_else(|| format!("osc code is not a valid DynamicColorNumber!?"))?;
Ok(OperatingSystemCommand::ResetDynamicColor(which_color))
}
fn parse_change_dynamic_color_number(idx: u8, osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse_change_dynamic_color_number(idx: u8, osc: &[&[u8]]) -> Result<Self> {
let which_color: DynamicColorNumber = FromPrimitive::from_u8(idx)
.ok_or_else(|| anyhow!("osc code is not a valid DynamicColorNumber!?"))?;
.ok_or_else(|| format!("osc code is not a valid DynamicColorNumber!?"))?;
let mut colors = vec![];
for spec in osc.iter().skip(1) {
if spec == b"?" {
@ -235,7 +235,7 @@ impl OperatingSystemCommand {
let spec = str::from_utf8(spec)?;
colors.push(ColorOrQuery::Color(
RgbColor::from_named_or_rgb_string(spec)
.ok_or_else(|| anyhow!("invalid color spec {:?}", spec))?,
.ok_or_else(|| format!("invalid color spec {:?}", spec))?,
));
}
}
@ -246,7 +246,7 @@ impl OperatingSystemCommand {
))
}
fn internal_parse(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn internal_parse(osc: &[&[u8]]) -> Result<Self> {
ensure!(!osc.is_empty(), "no params");
let p1str = String::from_utf8_lossy(osc[0]);
@ -268,7 +268,7 @@ impl OperatingSystemCommand {
} else {
OperatingSystemCommandCode::from_code(&p1str)
}
.ok_or_else(|| anyhow!("unknown code"))?;
.ok_or_else(|| format!("unknown code"))?;
macro_rules! single_string {
($variant:ident) => {{
@ -442,7 +442,7 @@ impl OperatingSystemCommandCode {
}
impl Display for OperatingSystemCommand {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "\x1b]")?;
macro_rules! single_string {
@ -532,20 +532,20 @@ pub enum FinalTermClick {
}
impl std::convert::TryFrom<&str> for FinalTermClick {
type Error = anyhow::Error;
fn try_from(s: &str) -> anyhow::Result<Self> {
type Error = crate::Error;
fn try_from(s: &str) -> Result<Self> {
match s {
"line" => Ok(Self::Line),
"m" => Ok(Self::MultipleLine),
"v" => Ok(Self::ConservativeVertical),
"w" => Ok(Self::SmartVertical),
_ => Err(anyhow!("invalid FinalTermClick {}", s)),
_ => bail!("invalid FinalTermClick {}", s),
}
}
}
impl Display for FinalTermClick {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self {
Self::Line => write!(f, "line"),
Self::MultipleLine => write!(f, "m"),
@ -575,20 +575,20 @@ impl Default for FinalTermPromptKind {
}
impl std::convert::TryFrom<&str> for FinalTermPromptKind {
type Error = anyhow::Error;
fn try_from(s: &str) -> anyhow::Result<Self> {
type Error = crate::Error;
fn try_from(s: &str) -> Result<Self> {
match s {
"i" => Ok(Self::Initial),
"r" => Ok(Self::RightSide),
"c" => Ok(Self::Continuation),
"s" => Ok(Self::Secondary),
_ => Err(anyhow!("invalid FinalTermPromptKind {}", s)),
_ => bail!("invalid FinalTermPromptKind {}", s),
}
}
}
impl Display for FinalTermPromptKind {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self {
Self::Initial => write!(f, "i"),
Self::RightSide => write!(f, "r"),
@ -644,7 +644,7 @@ pub enum FinalTermSemanticPrompt {
}
impl FinalTermSemanticPrompt {
fn parse(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse(osc: &[&[u8]]) -> Result<Self> {
ensure!(osc.len() > 1, "not enough args");
let param = String::from_utf8_lossy(osc[1]);
@ -721,7 +721,7 @@ impl FinalTermSemanticPrompt {
}));
}
anyhow::bail!(
bail!(
"invalid FinalTermSemanticPrompt p1:{:?}, params:{:?}",
param,
params
@ -730,7 +730,7 @@ impl FinalTermSemanticPrompt {
}
impl Display for FinalTermSemanticPrompt {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "133;")?;
match self {
Self::FreshLine => write!(f, "L")?,
@ -841,7 +841,7 @@ pub struct ITermFileData {
}
impl ITermFileData {
fn parse(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse(osc: &[&[u8]]) -> Result<Self> {
let mut params = HashMap::new();
// Unfortunately, the encoding for the file download data is
@ -904,7 +904,7 @@ impl ITermFileData {
.map(|s| *s != "0")
.unwrap_or(true);
let inline = params.get("inline").map(|s| *s != "0").unwrap_or(false);
let data = data.ok_or_else(|| anyhow!("didn't set data"))?;
let data = data.ok_or_else(|| format!("didn't set data"))?;
Ok(Self {
name,
size,
@ -918,10 +918,10 @@ impl ITermFileData {
}
impl Display for ITermFileData {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "File")?;
let mut sep = "=";
let emit_sep = |sep, f: &mut Formatter| -> Result<&str, FmtError> {
let emit_sep = |sep, f: &mut Formatter| -> std::result::Result<&str, FmtError> {
write!(f, "{}", sep)?;
Ok(";")
};
@ -974,7 +974,7 @@ impl Default for ITermDimension {
}
impl Display for ITermDimension {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
use self::ITermDimension::*;
match self {
Automatic => write!(f, "auto"),
@ -986,14 +986,14 @@ impl Display for ITermDimension {
}
impl std::str::FromStr for ITermDimension {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self> {
ITermDimension::parse(s)
}
}
impl ITermDimension {
fn parse(s: &str) -> anyhow::Result<Self> {
fn parse(s: &str) -> Result<Self> {
if s == "auto" {
Ok(ITermDimension::Automatic)
} else if s.ends_with("px") {
@ -1031,7 +1031,7 @@ impl ITermProprietary {
feature = "cargo-clippy",
allow(clippy::cyclomatic_complexity, clippy::cognitive_complexity)
)]
fn parse(osc: &[&[u8]]) -> anyhow::Result<Self> {
fn parse(osc: &[&[u8]]) -> Result<Self> {
// iTerm has a number of different styles of OSC parameter
// encodings, which makes this section of code a bit gnarly.
ensure!(osc.len() > 1, "not enough args");
@ -1039,7 +1039,7 @@ impl ITermProprietary {
let param = String::from_utf8_lossy(osc[1]);
let mut iter = param.splitn(2, '=');
let keyword = iter.next().ok_or_else(|| anyhow!("bad params"))?;
let keyword = iter.next().ok_or_else(|| format!("bad params"))?;
let p1 = iter.next();
macro_rules! single {
@ -1132,7 +1132,7 @@ impl ITermProprietary {
}
impl Display for ITermProprietary {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "1337;")?;
use self::ITermProprietary::*;
match self {

View File

@ -4,7 +4,7 @@
//! We use that as the foundation of our hyperlink support, and the game
//! plan is to then implicitly enable the hyperlink attribute for a cell
//! as we recognize linkable input text during print() processing.
use anyhow::{anyhow, ensure, Error};
use crate::{ensure, format_err, Result};
use regex::{Captures, Regex};
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Deserializer, Serialize};
@ -71,7 +71,7 @@ impl Hyperlink {
}
}
pub fn parse(osc: &[&[u8]]) -> Result<Option<Hyperlink>, Error> {
pub fn parse(osc: &[&[u8]]) -> Result<Option<Hyperlink>> {
ensure!(osc.len() == 3, "wrong param count");
if osc[1].is_empty() && osc[2].is_empty() {
// Clearing current hyperlink
@ -84,8 +84,8 @@ impl Hyperlink {
if !param_str.is_empty() {
for pair in param_str.split(':') {
let mut iter = pair.splitn(2, '=');
let key = iter.next().ok_or_else(|| anyhow!("bad params"))?;
let value = iter.next().ok_or_else(|| anyhow!("bad params"))?;
let key = iter.next().ok_or_else(|| format_err!("bad params"))?;
let value = iter.next().ok_or_else(|| format_err!("bad params"))?;
params.insert(key.to_owned(), value.to_owned());
}
}
@ -96,7 +96,7 @@ impl Hyperlink {
}
impl Display for Hyperlink {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> std::result::Result<(), FmtError> {
write!(f, "8;")?;
for (idx, (k, v)) in self.params.iter().enumerate() {
// TODO: protect against k, v containing : or =
@ -145,7 +145,7 @@ pub struct Rule {
}
#[cfg(feature = "use_serde")]
fn deserialize_regex<'de, D>(deserializer: D) -> Result<Regex, D::Error>
fn deserialize_regex<'de, D>(deserializer: D) -> std::result::Result<Regex, D::Error>
where
D: Deserializer<'de>,
{
@ -198,7 +198,7 @@ impl<'t> Match<'t> {
impl Rule {
/// Construct a new rule. It may fail if the regex is invalid.
pub fn new(regex: &str, format: &str) -> Result<Self, Error> {
pub fn new(regex: &str, format: &str) -> Result<Self> {
Ok(Self {
regex: Regex::new(regex)?,
format: format.to_owned(),

View File

@ -44,6 +44,7 @@ pub mod caps;
pub mod cell;
pub mod cellcluster;
pub mod color;
pub mod error;
pub mod escape;
pub mod hyperlink;
pub mod image;
@ -58,3 +59,5 @@ pub mod surface;
pub mod terminal;
#[cfg(feature = "widgets")]
pub mod widgets;
pub use error::{Context, Error, Result};

View File

@ -4,7 +4,7 @@
//! ```no_run
//! use termwiz::lineedit::{line_editor_terminal, NopLineEditorHost, LineEditor};
//!
//! fn main() -> anyhow::Result<()> {
//! fn main() -> termwiz::Result<()> {
//! let mut terminal = line_editor_terminal()?;
//! let mut editor = LineEditor::new(&mut terminal);
//! let mut host = NopLineEditorHost::default();
@ -42,6 +42,7 @@ use crate::input::{InputEvent, KeyCode, KeyEvent, Modifiers};
use crate::surface::change::ChangeSequence;
use crate::surface::{Change, Position};
use crate::terminal::{new_terminal, Terminal};
use crate::{bail, ensure, Result};
use unicode_segmentation::GraphemeCursor;
mod actions;
@ -56,7 +57,7 @@ pub use host::*;
/// ```no_run
/// use termwiz::lineedit::{line_editor_terminal, NopLineEditorHost, LineEditor};
///
/// fn main() -> anyhow::Result<()> {
/// fn main() -> termwiz::Result<()> {
/// let mut terminal = line_editor_terminal()?;
/// let mut editor = LineEditor::new(&mut terminal);
/// let mut host = NopLineEditorHost::default();
@ -142,7 +143,7 @@ impl<'term> LineEditor<'term> {
/// ```no_run
/// use termwiz::caps::{Capabilities, ProbeHints};
/// use termwiz::terminal::new_terminal;
/// use anyhow::Error;
/// use termwiz::Error;
/// // Disable mouse input in the line editor
/// let hints = ProbeHints::new_from_env()
/// .mouse_reporting(Some(false));
@ -165,7 +166,7 @@ impl<'term> LineEditor<'term> {
}
}
fn render(&mut self, host: &mut dyn LineEditorHost) -> anyhow::Result<()> {
fn render(&mut self, host: &mut dyn LineEditorHost) -> Result<()> {
let screen_size = self.terminal.get_screen_size()?;
let mut changes = ChangeSequence::new(screen_size.rows, screen_size.cols);
@ -300,8 +301,8 @@ impl<'term> LineEditor<'term> {
/// Control is not returned to the caller until a line has been
/// accepted, or until an error is detected.
/// Returns Ok(None) if the editor was cancelled eg: via CTRL-C.
pub fn read_line(&mut self, host: &mut dyn LineEditorHost) -> anyhow::Result<Option<String>> {
anyhow::ensure!(
pub fn read_line(&mut self, host: &mut dyn LineEditorHost) -> Result<Option<String>> {
ensure!(
self.state == EditorState::Inactive,
"recursive call to read_line!"
);
@ -786,11 +787,7 @@ impl<'term> LineEditor<'term> {
/// Applies the effect of the specified action to the line editor.
/// You don't normally need to call this unless you are defining
/// custom key mapping or custom actions in your embedding application.
pub fn apply_action(
&mut self,
host: &mut dyn LineEditorHost,
action: Action,
) -> anyhow::Result<()> {
pub fn apply_action(&mut self, host: &mut dyn LineEditorHost, action: Action) -> Result<()> {
// When searching, reinterpret history next/prev as repeated
// search actions in the appropriate direction
let action = match (action, &self.state) {
@ -950,7 +947,7 @@ impl<'term> LineEditor<'term> {
Ok(())
}
fn read_line_impl(&mut self, host: &mut dyn LineEditorHost) -> anyhow::Result<Option<String>> {
fn read_line_impl(&mut self, host: &mut dyn LineEditorHost) -> Result<Option<String>> {
self.line.clear();
self.cursor = 0;
self.history_pos = None;
@ -968,7 +965,7 @@ impl<'term> LineEditor<'term> {
EditorState::Searching { .. } | EditorState::Editing => {}
EditorState::Cancelled => return Ok(None),
EditorState::Accepted => return Ok(Some(self.line.clone())),
EditorState::Inactive => anyhow::bail!("editor is inactive during read line!?"),
EditorState::Inactive => bail!("editor is inactive during read line!?"),
}
} else {
self.render(host)?;
@ -980,7 +977,7 @@ impl<'term> LineEditor<'term> {
/// Create a `Terminal` with the recommended settings for use with
/// a `LineEditor`.
pub fn line_editor_terminal() -> anyhow::Result<impl Terminal> {
pub fn line_editor_terminal() -> Result<impl Terminal> {
let hints = ProbeHints::new_from_env().mouse_reporting(Some(false));
let caps = Capabilities::new_with_hints(hints)?;
new_terminal(caps)

View File

@ -4,5 +4,5 @@ pub mod windows;
pub trait RenderTty: std::io::Write {
/// Returns the (cols, rows) for the terminal
fn get_size_in_cells(&mut self) -> anyhow::Result<(usize, usize)>;
fn get_size_in_cells(&mut self) -> crate::Result<(usize, usize)>;
}

View File

@ -8,6 +8,7 @@ use crate::escape::OneBased;
use crate::image::TextureCoordinate;
use crate::render::RenderTty;
use crate::surface::{Change, CursorShape, CursorVisibility, Position};
use crate::Result;
use std::io::Write;
use terminfo::{capability as cap, Capability as TermInfoCapability};
@ -47,7 +48,7 @@ impl TerminfoRenderer {
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
fn flush_pending_attr<W: RenderTty + Write>(&mut self, out: &mut W) -> anyhow::Result<()> {
fn flush_pending_attr<W: RenderTty + Write>(&mut self, out: &mut W) -> Result<()> {
macro_rules! attr_on {
($cap:ident, $sgr:expr) => {
if let Some(attr) = self.get_capability::<cap::$cap>() {
@ -204,7 +205,7 @@ impl TerminfoRenderer {
Ok(())
}
fn cursor_up<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> anyhow::Result<()> {
fn cursor_up<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> Result<()> {
if n > 0 {
if let Some(attr) = self.get_capability::<cap::ParmUpCursor>() {
attr.expand().count(n).to(out.by_ref())?;
@ -215,7 +216,7 @@ impl TerminfoRenderer {
Ok(())
}
fn cursor_down<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> anyhow::Result<()> {
fn cursor_down<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> Result<()> {
if n > 0 {
if let Some(attr) = self.get_capability::<cap::ParmDownCursor>() {
attr.expand().count(n).to(out.by_ref())?;
@ -226,11 +227,7 @@ impl TerminfoRenderer {
Ok(())
}
fn cursor_y_relative<W: RenderTty + Write>(
&mut self,
y: isize,
out: &mut W,
) -> anyhow::Result<()> {
fn cursor_y_relative<W: RenderTty + Write>(&mut self, y: isize, out: &mut W) -> Result<()> {
if y > 0 {
self.cursor_down(y as u32, out)
} else {
@ -238,7 +235,7 @@ impl TerminfoRenderer {
}
}
fn cursor_left<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> anyhow::Result<()> {
fn cursor_left<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> Result<()> {
if n > 0 {
if let Some(attr) = self.get_capability::<cap::ParmLeftCursor>() {
attr.expand().count(n).to(out.by_ref())?;
@ -249,7 +246,7 @@ impl TerminfoRenderer {
Ok(())
}
fn cursor_right<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> anyhow::Result<()> {
fn cursor_right<W: RenderTty + Write>(&mut self, n: u32, out: &mut W) -> Result<()> {
if n > 0 {
if let Some(attr) = self.get_capability::<cap::ParmRightCursor>() {
attr.expand().count(n).to(out.by_ref())?;
@ -260,11 +257,7 @@ impl TerminfoRenderer {
Ok(())
}
fn cursor_x_relative<W: RenderTty + Write>(
&mut self,
x: isize,
out: &mut W,
) -> anyhow::Result<()> {
fn cursor_x_relative<W: RenderTty + Write>(&mut self, x: isize, out: &mut W) -> Result<()> {
if x > 0 {
self.cursor_right(x as u32, out)
} else {
@ -277,7 +270,7 @@ impl TerminfoRenderer {
x: u32,
y: u32,
out: &mut W,
) -> anyhow::Result<()> {
) -> Result<()> {
if x == 0 && y == 0 {
if let Some(attr) = self.get_capability::<cap::CursorHome>() {
attr.expand().to(out.by_ref())?;
@ -312,7 +305,7 @@ impl TerminfoRenderer {
&mut self,
changes: &[Change],
out: &mut W,
) -> anyhow::Result<()> {
) -> Result<()> {
macro_rules! record {
($accesor:ident, $value:expr) => {
self.attr_apply(|attr| {
@ -681,6 +674,7 @@ impl TerminfoRenderer {
#[cfg(all(test, unix))]
mod test {
use super::*;
use crate::bail;
use crate::caps::ProbeHints;
use crate::color::{AnsiColor, ColorAttribute, RgbColor};
use crate::escape::parser::Parser;
@ -689,7 +683,6 @@ mod test {
use crate::terminal::unix::{Purge, SetAttributeWhen, UnixTty};
use crate::terminal::ScreenSize;
use crate::terminal::{cast, Terminal, TerminalWaker};
use anyhow::bail;
use libc::winsize;
use std::io::{Error as IoError, ErrorKind, Read, Result as IoResult, Write};
use std::mem;
@ -736,41 +729,37 @@ mod test {
}
}
impl RenderTty for FakeTty {
fn get_size_in_cells(&mut self) -> anyhow::Result<(usize, usize)> {
fn get_size_in_cells(&mut self) -> Result<(usize, usize)> {
Ok((self.size.ws_col as usize, self.size.ws_row as usize))
}
}
impl UnixTty for FakeTty {
fn get_size(&mut self) -> anyhow::Result<winsize> {
fn get_size(&mut self) -> Result<winsize> {
Ok(self.size.clone())
}
fn set_size(&mut self, size: winsize) -> anyhow::Result<()> {
fn set_size(&mut self, size: winsize) -> Result<()> {
self.size = size.clone();
Ok(())
}
fn get_termios(&mut self) -> anyhow::Result<Termios> {
fn get_termios(&mut self) -> Result<Termios> {
Ok(self.termios.clone())
}
fn set_termios(
&mut self,
termios: &Termios,
_when: SetAttributeWhen,
) -> anyhow::Result<()> {
fn set_termios(&mut self, termios: &Termios, _when: SetAttributeWhen) -> Result<()> {
self.termios = termios.clone();
Ok(())
}
/// Waits until all written data has been transmitted.
fn drain(&mut self) -> anyhow::Result<()> {
fn drain(&mut self) -> Result<()> {
Ok(())
}
fn purge(&mut self, _purge: Purge) -> anyhow::Result<()> {
fn purge(&mut self, _purge: Purge) -> Result<()> {
Ok(())
}
}
impl Read for FakeTty {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize, IoError> {
fn read(&mut self, _buf: &mut [u8]) -> std::result::Result<usize, IoError> {
Err(IoError::new(ErrorKind::Other, "not implemented"))
}
}
@ -807,27 +796,27 @@ mod test {
}
impl Terminal for FakeTerm {
fn set_raw_mode(&mut self) -> anyhow::Result<()> {
fn set_raw_mode(&mut self) -> Result<()> {
bail!("not implemented");
}
fn set_cooked_mode(&mut self) -> anyhow::Result<()> {
fn set_cooked_mode(&mut self) -> Result<()> {
bail!("not implemented");
}
fn enter_alternate_screen(&mut self) -> anyhow::Result<()> {
fn enter_alternate_screen(&mut self) -> Result<()> {
bail!("not implemented");
}
fn exit_alternate_screen(&mut self) -> anyhow::Result<()> {
fn exit_alternate_screen(&mut self) -> Result<()> {
bail!("not implemented");
}
fn render(&mut self, changes: &[Change]) -> anyhow::Result<()> {
fn render(&mut self, changes: &[Change]) -> Result<()> {
self.renderer.render_to(changes, &mut self.write)
}
fn get_screen_size(&mut self) -> anyhow::Result<ScreenSize> {
fn get_screen_size(&mut self) -> Result<ScreenSize> {
let size = self.write.get_size()?;
Ok(ScreenSize {
rows: cast(size.ws_row)?,
@ -837,7 +826,7 @@ mod test {
})
}
fn set_screen_size(&mut self, size: ScreenSize) -> anyhow::Result<()> {
fn set_screen_size(&mut self, size: ScreenSize) -> Result<()> {
let size = winsize {
ws_row: cast(size.rows)?,
ws_col: cast(size.cols)?,
@ -848,11 +837,11 @@ mod test {
self.write.set_size(size)
}
fn flush(&mut self) -> anyhow::Result<()> {
fn flush(&mut self) -> Result<()> {
Ok(())
}
fn poll_input(&mut self, _wait: Option<Duration>) -> anyhow::Result<Option<InputEvent>> {
fn poll_input(&mut self, _wait: Option<Duration>) -> Result<Option<InputEvent>> {
bail!("not implemented");
}

View File

@ -5,6 +5,7 @@ use crate::cell::{AttributeChange, CellAttributes, Underline};
use crate::color::{AnsiColor, ColorAttribute};
use crate::surface::{Change, Position};
use crate::terminal::windows::ConsoleOutputHandle;
use crate::Result;
use num_traits::FromPrimitive;
use std::io::Write;
use winapi::shared::minwindef::WORD;
@ -152,10 +153,7 @@ impl ScreenBuffer {
end
}
fn do_cursor_y_scroll<B: ConsoleOutputHandle + Write>(
&mut self,
out: &mut B,
) -> anyhow::Result<()> {
fn do_cursor_y_scroll<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> Result<()> {
if self.cursor_y >= self.rows {
self.dirty = true;
let lines_to_scroll = self.cursor_y.saturating_sub(self.rows) + 1;
@ -172,7 +170,7 @@ impl ScreenBuffer {
x: usize,
y: usize,
out: &mut B,
) -> anyhow::Result<()> {
) -> Result<()> {
self.cursor_x = x;
self.cursor_y = y;
@ -190,7 +188,7 @@ impl ScreenBuffer {
t: &str,
attr: WORD,
out: &mut B,
) -> anyhow::Result<()> {
) -> Result<()> {
for c in t.chars() {
match c {
'\r' => {
@ -222,7 +220,7 @@ impl ScreenBuffer {
Ok(())
}
fn flush<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> anyhow::Result<()> {
fn flush<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> Result<()> {
self.flush_screen(out)?;
let info = out.get_buffer_info()?;
out.set_cursor_position(
@ -234,7 +232,7 @@ impl ScreenBuffer {
Ok(())
}
fn flush_screen<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> anyhow::Result<()> {
fn flush_screen<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> Result<()> {
if self.dirty {
out.flush()?;
out.set_buffer_contents(&self.buf)?;
@ -244,7 +242,7 @@ impl ScreenBuffer {
Ok(())
}
fn reread_buffer<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> anyhow::Result<()> {
fn reread_buffer<B: ConsoleOutputHandle + Write>(&mut self, out: &mut B) -> Result<()> {
self.buf = out.get_buffer_contents()?;
self.dirty = false;
Ok(())
@ -256,7 +254,7 @@ impl ScreenBuffer {
region_size: usize,
scroll_count: isize,
out: &mut B,
) -> anyhow::Result<()> {
) -> Result<()> {
if region_size > 0 && scroll_count != 0 {
self.flush_screen(out)?;
let info = out.get_buffer_info()?;
@ -296,7 +294,7 @@ impl WindowsConsoleRenderer {
&mut self,
changes: &[Change],
out: &mut B,
) -> anyhow::Result<()> {
) -> Result<()> {
out.flush()?;
let info = out.get_buffer_info()?;

View File

@ -2,7 +2,7 @@
use crate::surface::{SequenceNo, Surface};
use crate::terminal::Terminal;
use anyhow::Error;
use crate::Result;
use std::ops::{Deref, DerefMut};
/// `BufferedTerminal` is a convenience wrapper around both
@ -23,7 +23,7 @@ pub struct BufferedTerminal<T: Terminal> {
impl<T: Terminal> BufferedTerminal<T> {
/// Create a new `BufferedTerminal` with a `Surface` of
/// a matching size.
pub fn new(mut terminal: T) -> Result<Self, Error> {
pub fn new(mut terminal: T) -> Result<Self> {
let size = terminal.get_screen_size()?;
let surface = Surface::new(size.cols, size.rows);
Ok(Self {
@ -47,7 +47,7 @@ impl<T: Terminal> BufferedTerminal<T> {
/// Applications typically build in a refresh function (CTRL-L
/// is common for unix applications) to request a repaint.
/// You can use the `repaint` function for that situation.
pub fn flush(&mut self) -> Result<(), Error> {
pub fn flush(&mut self) -> Result<()> {
{
let (seq, changes) = self.surface.get_changes(self.seqno);
// If we encounter an error during rendering, we want to
@ -64,7 +64,7 @@ impl<T: Terminal> BufferedTerminal<T> {
/// Clears the screen and re-draws the surface contents onto
/// the Terminal.
pub fn repaint(&mut self) -> Result<(), Error> {
pub fn repaint(&mut self) -> Result<()> {
self.seqno = 0;
self.flush()
}
@ -93,7 +93,7 @@ impl<T: Terminal> BufferedTerminal<T> {
/// consume the input records. Such a thing is possible, but is
/// better suited for a higher level abstraction than this basic
/// `BufferedTerminal` interface.
pub fn check_for_resize(&mut self) -> Result<bool, Error> {
pub fn check_for_resize(&mut self) -> Result<bool> {
let size = self.terminal.get_screen_size()?;
let (width, height) = self.surface.dimensions();

View File

@ -3,7 +3,7 @@
use crate::caps::Capabilities;
use crate::input::InputEvent;
use crate::surface::Change;
use anyhow::{anyhow, Error};
use crate::{format_err, Result};
use num_traits::NumCast;
use std::fmt::Display;
use std::time::Duration;
@ -55,27 +55,27 @@ pub trait Terminal {
/// read as the user presses keys, disables local echo, so keys
/// pressed by the user do not implicitly render to the terminal
/// output, and disables canonicalization of unix newlines to CRLF.
fn set_raw_mode(&mut self) -> Result<(), Error>;
fn set_cooked_mode(&mut self) -> anyhow::Result<()>;
fn set_raw_mode(&mut self) -> Result<()>;
fn set_cooked_mode(&mut self) -> Result<()>;
/// Enter the alternate screen. The alternate screen will be left
/// automatically when the `Terminal` is dropped.
fn enter_alternate_screen(&mut self) -> Result<(), Error>;
fn enter_alternate_screen(&mut self) -> Result<()>;
/// Exit the alternate screen.
fn exit_alternate_screen(&mut self) -> Result<(), Error>;
fn exit_alternate_screen(&mut self) -> Result<()>;
/// Queries the current screen size, returning width, height.
fn get_screen_size(&mut self) -> Result<ScreenSize, Error>;
fn get_screen_size(&mut self) -> Result<ScreenSize>;
/// Sets the current screen size
fn set_screen_size(&mut self, size: ScreenSize) -> Result<(), Error>;
fn set_screen_size(&mut self, size: ScreenSize) -> Result<()>;
/// Render a series of changes to the terminal output
fn render(&mut self, changes: &[Change]) -> Result<(), Error>;
fn render(&mut self, changes: &[Change]) -> Result<()>;
/// Flush any buffered output
fn flush(&mut self) -> Result<(), Error>;
fn flush(&mut self) -> Result<()>;
/// Check for a parsed input event.
/// `wait` indicates the behavior in the case that no input is
@ -89,7 +89,7 @@ pub trait Terminal {
/// The possible values returned as `InputEvent`s depend on the
/// mode of the terminal. Most values are not returned unless
/// the terminal is set to raw mode.
fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>, Error>;
fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>>;
fn waker(&self) -> TerminalWaker;
}
@ -112,10 +112,10 @@ pub type SystemTerminal = WindowsTerminal;
/// If you have a more advanced use case you will want to look to the
/// constructors for `UnixTerminal` and `WindowsTerminal` and call whichever
/// one is most suitable for your needs.
pub fn new_terminal(caps: Capabilities) -> Result<impl Terminal, Error> {
pub fn new_terminal(caps: Capabilities) -> Result<impl Terminal> {
SystemTerminal::new(caps)
}
pub(crate) fn cast<T: NumCast + Display + Copy, U: NumCast>(n: T) -> Result<U, Error> {
num_traits::cast(n).ok_or_else(|| anyhow!("{} is out of bounds for this system", n))
pub(crate) fn cast<T: NumCast + Display + Copy, U: NumCast>(n: T) -> Result<U> {
num_traits::cast(n).ok_or_else(|| format_err!("{} is out of bounds for this system", n))
}

View File

@ -1,5 +1,5 @@
use crate::render::RenderTty;
use anyhow::{anyhow, bail, Context, Error};
use crate::{bail, Context, Result};
use filedescriptor::{poll, pollfd, FileDescriptor, POLLIN};
use libc::{self, winsize};
use signal_hook::{self, SigId};
@ -42,13 +42,13 @@ pub enum SetAttributeWhen {
}
pub trait UnixTty {
fn get_size(&mut self) -> Result<winsize, Error>;
fn set_size(&mut self, size: winsize) -> Result<(), Error>;
fn get_termios(&mut self) -> Result<Termios, Error>;
fn set_termios(&mut self, termios: &Termios, when: SetAttributeWhen) -> Result<(), Error>;
fn get_size(&mut self) -> Result<winsize>;
fn set_size(&mut self, size: winsize) -> Result<()>;
fn get_termios(&mut self) -> Result<Termios>;
fn set_termios(&mut self, termios: &Termios, when: SetAttributeWhen) -> Result<()>;
/// Waits until all written data has been transmitted.
fn drain(&mut self) -> Result<(), Error>;
fn purge(&mut self, purge: Purge) -> Result<(), Error>;
fn drain(&mut self) -> Result<()>;
fn purge(&mut self, purge: Purge) -> Result<()>;
}
pub struct TtyReadHandle {
@ -60,14 +60,14 @@ impl TtyReadHandle {
Self { fd }
}
fn set_blocking(&mut self, blocking: Blocking) -> Result<(), Error> {
fn set_blocking(&mut self, blocking: Blocking) -> Result<()> {
self.fd.set_non_blocking(blocking == Blocking::DoNotWait)?;
Ok(())
}
}
impl Read for TtyReadHandle {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, IoError> {
let size =
unsafe { libc::read(self.fd.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) };
if size == -1 {
@ -91,7 +91,7 @@ impl TtyWriteHandle {
}
}
fn flush_local_buffer(&mut self) -> Result<(), IoError> {
fn flush_local_buffer(&mut self) -> std::result::Result<(), IoError> {
if !self.write_buffer.is_empty() {
self.fd.write_all(&self.write_buffer)?;
self.write_buffer.clear();
@ -101,7 +101,7 @@ impl TtyWriteHandle {
}
impl Write for TtyWriteHandle {
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, IoError> {
if self.write_buffer.len() + buf.len() > self.write_buffer.capacity() {
self.flush()?;
}
@ -112,7 +112,7 @@ impl Write for TtyWriteHandle {
}
}
fn flush(&mut self) -> Result<(), IoError> {
fn flush(&mut self) -> std::result::Result<(), IoError> {
self.flush_local_buffer()?;
self.drain()
.map_err(|e| IoError::new(ErrorKind::Other, format!("{}", e)))?;
@ -121,14 +121,14 @@ impl Write for TtyWriteHandle {
}
impl RenderTty for TtyWriteHandle {
fn get_size_in_cells(&mut self) -> anyhow::Result<(usize, usize)> {
fn get_size_in_cells(&mut self) -> Result<(usize, usize)> {
let size = self.get_size()?;
Ok((size.ws_col as usize, size.ws_row as usize))
}
}
impl UnixTty for TtyWriteHandle {
fn get_size(&mut self) -> Result<winsize, Error> {
fn get_size(&mut self) -> Result<winsize> {
let mut size: winsize = unsafe { mem::zeroed() };
if unsafe { libc::ioctl(self.fd.as_raw_fd(), libc::TIOCGWINSZ as _, &mut size) } != 0 {
bail!("failed to ioctl(TIOCGWINSZ): {}", IoError::last_os_error());
@ -136,7 +136,7 @@ impl UnixTty for TtyWriteHandle {
Ok(size)
}
fn set_size(&mut self, size: winsize) -> Result<(), Error> {
fn set_size(&mut self, size: winsize) -> Result<()> {
if unsafe {
libc::ioctl(
self.fd.as_raw_fd(),
@ -154,11 +154,11 @@ impl UnixTty for TtyWriteHandle {
Ok(())
}
fn get_termios(&mut self) -> Result<Termios, Error> {
fn get_termios(&mut self) -> Result<Termios> {
Termios::from_fd(self.fd.as_raw_fd()).context("get_termios failed")
}
fn set_termios(&mut self, termios: &Termios, when: SetAttributeWhen) -> Result<(), Error> {
fn set_termios(&mut self, termios: &Termios, when: SetAttributeWhen) -> Result<()> {
let when = match when {
SetAttributeWhen::Now => TCSANOW,
SetAttributeWhen::AfterDrainOutputQueue => TCSADRAIN,
@ -167,11 +167,11 @@ impl UnixTty for TtyWriteHandle {
tcsetattr(self.fd.as_raw_fd(), when, termios).context("set_termios failed")
}
fn drain(&mut self) -> Result<(), Error> {
fn drain(&mut self) -> Result<()> {
tcdrain(self.fd.as_raw_fd()).context("tcdrain failed")
}
fn purge(&mut self, purge: Purge) -> Result<(), Error> {
fn purge(&mut self, purge: Purge) -> Result<()> {
let param = match purge {
Purge::InputQueue => TCIFLUSH,
Purge::OutputQueue => TCOFLUSH,
@ -203,7 +203,7 @@ impl UnixTerminal {
/// Note that this will duplicate the underlying file descriptors
/// and will no longer participate in the stdin/stdout locking
/// provided by the rust standard library.
pub fn new_from_stdio(caps: Capabilities) -> Result<UnixTerminal, Error> {
pub fn new_from_stdio(caps: Capabilities) -> Result<UnixTerminal> {
Self::new_with(caps, &stdin(), &stdout())
}
@ -211,7 +211,7 @@ impl UnixTerminal {
caps: Capabilities,
read: &A,
write: &B,
) -> Result<UnixTerminal, Error> {
) -> Result<UnixTerminal> {
let mut read = TtyReadHandle::new(FileDescriptor::dup(read)?);
let mut write = TtyWriteHandle::new(FileDescriptor::dup(write)?);
let saved_termios = write.get_termios()?;
@ -248,14 +248,14 @@ impl UnixTerminal {
/// (/dev/tty) and build a `UnixTerminal` from there. This will
/// yield a terminal even if the stdio streams have been redirected,
/// provided that the process has an associated controlling terminal.
pub fn new(caps: Capabilities) -> Result<UnixTerminal, Error> {
pub fn new(caps: Capabilities) -> Result<UnixTerminal> {
let file = OpenOptions::new().read(true).write(true).open("/dev/tty")?;
Self::new_with(caps, &file, &file)
}
/// Test whether we caught delivery of SIGWINCH.
/// If so, yield an `InputEvent` with the current size of the tty.
fn caught_sigwinch(&mut self) -> Result<Option<InputEvent>, Error> {
fn caught_sigwinch(&mut self) -> Result<Option<InputEvent>> {
let mut buf = [0u8; 64];
match self.sigwinch_pipe.read(&mut buf) {
@ -272,7 +272,7 @@ impl UnixTerminal {
{
Ok(None)
}
Err(e) => Err(anyhow!("failed to read sigwinch pipe {}", e)),
Err(e) => bail!("failed to read sigwinch pipe {}", e),
}
}
}
@ -283,7 +283,7 @@ pub struct UnixTerminalWaker {
}
impl UnixTerminalWaker {
pub fn wake(&self) -> Result<(), IoError> {
pub fn wake(&self) -> std::result::Result<(), IoError> {
let mut pipe = self.pipe.lock().unwrap();
match pipe.write(b"W") {
Err(e) => match e.kind() {
@ -296,7 +296,7 @@ impl UnixTerminalWaker {
}
impl Terminal for UnixTerminal {
fn set_raw_mode(&mut self) -> Result<(), Error> {
fn set_raw_mode(&mut self) -> Result<()> {
let mut raw = self.write.get_termios()?;
cfmakeraw(&mut raw);
self.write
@ -327,12 +327,12 @@ impl Terminal for UnixTerminal {
Ok(())
}
fn set_cooked_mode(&mut self) -> anyhow::Result<()> {
fn set_cooked_mode(&mut self) -> Result<()> {
self.write
.set_termios(&self.saved_termios, SetAttributeWhen::Now)
}
fn enter_alternate_screen(&mut self) -> Result<(), Error> {
fn enter_alternate_screen(&mut self) -> Result<()> {
if !self.in_alternate_screen {
write!(
self.write,
@ -346,7 +346,7 @@ impl Terminal for UnixTerminal {
Ok(())
}
fn exit_alternate_screen(&mut self) -> Result<(), Error> {
fn exit_alternate_screen(&mut self) -> Result<()> {
if self.in_alternate_screen {
write!(
self.write,
@ -360,7 +360,7 @@ impl Terminal for UnixTerminal {
Ok(())
}
fn get_screen_size(&mut self) -> Result<ScreenSize, Error> {
fn get_screen_size(&mut self) -> Result<ScreenSize> {
let size = self.write.get_size()?;
Ok(ScreenSize {
rows: cast(size.ws_row)?,
@ -370,7 +370,7 @@ impl Terminal for UnixTerminal {
})
}
fn set_screen_size(&mut self, size: ScreenSize) -> Result<(), Error> {
fn set_screen_size(&mut self, size: ScreenSize) -> Result<()> {
let size = winsize {
ws_row: cast(size.rows)?,
ws_col: cast(size.cols)?,
@ -380,14 +380,14 @@ impl Terminal for UnixTerminal {
self.write.set_size(size)
}
fn render(&mut self, changes: &[Change]) -> Result<(), Error> {
fn render(&mut self, changes: &[Change]) -> Result<()> {
self.renderer.render_to(changes, &mut self.write)
}
fn flush(&mut self) -> Result<(), Error> {
fn flush(&mut self) -> Result<()> {
self.write.flush().context("flush failed")
}
fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>, Error> {
fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>> {
if let Some(event) = self.input_queue.pop_front() {
return Ok(Some(event));
}
@ -434,10 +434,10 @@ impl Terminal for UnixTerminal {
Ok(None)
}
} else {
Err(anyhow!("poll(2) error: {}", err))
bail!("poll(2) error: {}", err)
}
}
Err(err) => Err(anyhow!("poll(2) error: {}", err)),
Err(err) => bail!("poll(2) error: {}", err),
};
};
@ -462,7 +462,7 @@ impl Terminal for UnixTerminal {
}
Err(ref e)
if e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(anyhow!("failed to read input {}", e)),
Err(e) => bail!("failed to read input {}", e),
}
}

View File

@ -1,5 +1,5 @@
use crate::istty::IsTty;
use anyhow::{anyhow, bail, Error};
use crate::{bail, format_err, Error};
use filedescriptor::{FileDescriptor, OwnedHandle};
use std::cmp::{max, min};
use std::collections::VecDeque;
@ -52,8 +52,8 @@ pub trait ConsoleOutputHandle {
fn set_attr(&mut self, attr: u16) -> Result<(), Error>;
fn set_cursor_position(&mut self, x: i16, y: i16) -> Result<(), Error>;
fn get_buffer_info(&mut self) -> Result<CONSOLE_SCREEN_BUFFER_INFO, Error>;
fn get_buffer_contents(&mut self) -> anyhow::Result<Vec<CHAR_INFO>>;
fn set_buffer_contents(&mut self, buffer: &[CHAR_INFO]) -> anyhow::Result<()>;
fn get_buffer_contents(&mut self) -> Result<Vec<CHAR_INFO>>;
fn set_buffer_contents(&mut self, buffer: &[CHAR_INFO]) -> Result<()>;
fn set_viewport(&mut self, left: i16, top: i16, right: i16, bottom: i16) -> Result<(), Error>;
fn scroll_region(
&mut self,
@ -157,7 +157,7 @@ fn dimensions_from_buffer_info(info: CONSOLE_SCREEN_BUFFER_INFO) -> (usize, usiz
}
impl RenderTty for OutputHandle {
fn get_size_in_cells(&mut self) -> anyhow::Result<(usize, usize)> {
fn get_size_in_cells(&mut self) -> Result<(usize, usize)> {
let info = self.get_buffer_info()?;
let (cols, rows) = dimensions_from_buffer_info(info);
@ -298,7 +298,7 @@ impl ConsoleOutputHandle for OutputHandle {
Ok(())
}
fn get_buffer_contents(&mut self) -> anyhow::Result<Vec<CHAR_INFO>> {
fn get_buffer_contents(&mut self) -> Result<Vec<CHAR_INFO>> {
let info = self.get_buffer_info()?;
let cols = info.dwSize.X as usize;
@ -335,12 +335,12 @@ impl ConsoleOutputHandle for OutputHandle {
Ok(res)
}
fn set_buffer_contents(&mut self, buffer: &[CHAR_INFO]) -> anyhow::Result<()> {
fn set_buffer_contents(&mut self, buffer: &[CHAR_INFO]) -> Result<()> {
let info = self.get_buffer_info()?;
let cols = info.dwSize.X as usize;
let rows = 1 + info.srWindow.Bottom as usize - info.srWindow.Top as usize;
anyhow::ensure!(
ensure!(
rows * cols == buffer.len(),
"buffer size doesn't match screen size"
);
@ -548,7 +548,7 @@ impl WindowsTerminal {
Ok(terminal)
}
fn enable_virtual_terminal_processing_if_needed(&mut self) -> anyhow::Result<()> {
fn enable_virtual_terminal_processing_if_needed(&mut self) -> Result<()> {
match &self.renderer {
Renderer::Terminfo(_) => self.enable_virtual_terminal_processing(),
Renderer::Windows(_) => Ok(()),
@ -605,7 +605,7 @@ impl Terminal for WindowsTerminal {
)
}
fn set_cooked_mode(&mut self) -> anyhow::Result<()> {
fn set_cooked_mode(&mut self) -> Result<()> {
let mode = self.output_handle.get_output_mode()?;
self.output_handle
.set_output_mode(mode & !DISABLE_NEWLINE_AUTO_RETURN)
@ -671,7 +671,7 @@ impl Terminal for WindowsTerminal {
fn flush(&mut self) -> Result<(), Error> {
self.output_handle
.flush()
.map_err(|e| anyhow!("flush failed: {}", e))
.map_err(|e| format_err!("flush failed: {}", e))
}
fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>, Error> {

View File

@ -1,7 +1,7 @@
//! This module provides some automatic layout functionality for widgets.
//! The parameters are similar to those that you may have encountered
//! in HTML, but do not fully recreate the layout model.
use anyhow::{anyhow, Error};
use crate::{format_err, Error, Result};
use cassowary::strength::{REQUIRED, STRONG, WEAK};
use cassowary::WeightedRelation::*;
use cassowary::{AddConstraintError, Expression, Solver, SuggestValueError, Variable};
@ -185,13 +185,13 @@ pub struct LaidOutWidget {
fn suggesterr(e: SuggestValueError) -> Error {
match e {
SuggestValueError::UnknownEditVariable => anyhow!("Unknown edit variable"),
SuggestValueError::InternalSolverError(e) => anyhow!("Internal solver error: {}", e),
SuggestValueError::UnknownEditVariable => format_err!("Unknown edit variable"),
SuggestValueError::InternalSolverError(e) => format_err!("Internal solver error: {}", e),
}
}
fn adderr(e: AddConstraintError) -> Error {
anyhow!("{:?}", e)
format_err!("{:?}", e)
}
impl Default for LayoutState {
@ -246,7 +246,7 @@ impl LayoutState {
screen_width: usize,
screen_height: usize,
root_widget: WidgetId,
) -> Result<Vec<LaidOutWidget>, Error> {
) -> Result<Vec<LaidOutWidget>> {
self.solver
.suggest_value(self.screen_width, screen_width as f64)
.map_err(suggesterr)?;
@ -279,11 +279,11 @@ impl LayoutState {
parent_left: usize,
parent_top: usize,
results: &mut Vec<LaidOutWidget>,
) -> Result<(), Error> {
) -> Result<()> {
let state = self
.widget_states
.get(&widget)
.ok_or_else(|| anyhow!("widget has no solver state"))?;
.ok_or_else(|| format_err!("widget has no solver state"))?;
let width = self.solver.get_value(state.width) as usize;
let height = self.solver.get_value(state.height) as usize;
let left = self.solver.get_value(state.left) as usize;
@ -313,11 +313,11 @@ impl LayoutState {
parent_height: Variable,
parent_left: Option<Variable>,
parent_top: Option<Variable>,
) -> Result<WidgetState, Error> {
) -> Result<WidgetState> {
let state = self
.widget_states
.get(&widget)
.ok_or_else(|| anyhow!("widget has no solver state"))?
.ok_or_else(|| format_err!("widget has no solver state"))?
.clone();
let is_root_widget = parent_left.is_none();

View File

@ -4,7 +4,7 @@
use crate::color::ColorAttribute;
use crate::input::InputEvent;
use crate::surface::{Change, CursorShape, Position, SequenceNo, Surface};
use anyhow::Error;
use crate::{Error, Result};
use fnv::FnvHasher;
use std::collections::{HashMap, VecDeque};
use std::hash::BuildHasherDefault;
@ -309,7 +309,7 @@ impl<'widget> Ui<'widget> {
}
}
pub fn process_event_queue(&mut self) -> Result<(), Error> {
pub fn process_event_queue(&mut self) -> Result<()> {
while let Some(event) = self.input_queue.pop_front() {
match event {
WidgetEvent::Input(InputEvent::Resized { rows, cols }) => {
@ -354,7 +354,7 @@ impl<'widget> Ui<'widget> {
id: WidgetId,
screen: &mut Surface,
abs_coords: &ScreenRelativeCoords,
) -> Result<(), Error> {
) -> Result<()> {
let coords = {
let render_data = self.render.get_mut(&id).unwrap();
let surface = &mut render_data.surface;
@ -389,7 +389,7 @@ impl<'widget> Ui<'widget> {
/// Reconsider the layout constraints and apply them.
/// Returns true if the layout was changed, false if no changes were made.
fn compute_layout(&mut self, width: usize, height: usize) -> Result<bool, Error> {
fn compute_layout(&mut self, width: usize, height: usize) -> Result<bool> {
let mut layout = layout::LayoutState::new();
let root = self.graph.root.unwrap();
@ -421,7 +421,7 @@ impl<'widget> Ui<'widget> {
&mut self,
layout: &mut layout::LayoutState,
widget: WidgetId,
) -> Result<(), Error> {
) -> Result<()> {
let constraints = self.render[&widget].widget.get_size_constraints();
let children = self.graph.children(widget).to_vec();
@ -437,7 +437,7 @@ impl<'widget> Ui<'widget> {
/// This has the side effect of clearing out any unconsumed input queue.
/// Returns true if the Ui may need to be updated again; for example,
/// if the most recent update operation changed layout.
pub fn render_to_screen(&mut self, screen: &mut Surface) -> Result<bool, Error> {
pub fn render_to_screen(&mut self, screen: &mut Surface) -> Result<bool> {
if let Some(root) = self.graph.root {
let (width, height) = screen.dimensions();
// Render from scratch into a fresh screen buffer

View File

@ -53,7 +53,7 @@ fn run_confirmation_app(message: &str, term: &mut TermWizTerminal) -> anyhow::Re
No,
}
let render = |term: &mut TermWizTerminal, active: ActiveButton| -> anyhow::Result<()> {
let render = |term: &mut TermWizTerminal, active: ActiveButton| -> termwiz::Result<()> {
let mut changes = vec![
Change::ClearScreen(ColorAttribute::Default),
Change::CursorVisibility(CursorVisibility::Hidden),

View File

@ -165,7 +165,7 @@ pub fn launcher(
active_idx: usize,
entries: &[Entry],
term: &mut TermWizTerminal,
) -> anyhow::Result<()> {
) -> termwiz::Result<()> {
let mut changes = vec![
Change::ClearScreen(ColorAttribute::Default),
Change::CursorPosition {

View File

@ -26,7 +26,7 @@ pub fn tab_navigator(
active_tab_idx: usize,
tab_list: &[(String, TabId, usize)],
term: &mut TermWizTerminal,
) -> anyhow::Result<()> {
) -> termwiz::Result<()> {
// let dims = term.get_screen_size()?;
let mut changes = vec![
Change::ClearScreen(ColorAttribute::Default),