#[cfg(feature = "pyffi")]
use pyo3::{exceptions::PyValueError, prelude::*};
#[derive(Clone, Debug)]
pub struct OutOfBoundsError {
pub value: usize,
pub expected: core::ops::RangeInclusive<usize>,
}
impl OutOfBoundsError {
pub fn new<I: Into<usize>>(value: I, expected: core::ops::RangeInclusive<usize>) -> Self {
Self {
value: value.into(),
expected,
}
}
}
impl core::fmt::Display for OutOfBoundsError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.write_fmt(format_args!(
"{} does not fit into range {}..={}",
self.value,
self.expected.start(),
self.expected.end()
))
}
}
#[cfg(feature = "pyffi")]
impl From<OutOfBoundsError> for PyErr {
fn from(value: OutOfBoundsError) -> Self {
pyo3::exceptions::PyIndexError::new_err(value.to_string())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ColorFormatError {
UnknownFormat,
UnexpectedCharacters,
NoOpeningParenthesis,
NoClosingParenthesis,
UnknownColorSpace,
MissingCoordinate,
OversizedCoordinate,
MalformedHex,
MalformedFloat,
TooManyCoordinates,
WrongThemeColor,
MalformedThemeColor,
}
impl core::fmt::Display for ColorFormatError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use ColorFormatError::*;
match *self {
UnknownFormat => f.write_str(
"color format should start with `#`, `color()`, `oklab()`, `oklch()`, or `rgb:`",
),
UnexpectedCharacters => {
f.write_str("color format should contain only valid ASCII characters")
}
NoOpeningParenthesis => {
f.write_str("color format should include an opening parenthesis but has none")
}
NoClosingParenthesis => {
f.write_str("color format should include a closing parenthesis but has none")
}
UnknownColorSpace => {
f.write_str("color format should have known color space but does not")
}
MissingCoordinate => {
f.write_str("color format should have 3 coordinates but is missing one")
}
OversizedCoordinate => {
f.write_str("color format coordinates should have 1-4 hex digits but one has more")
}
MalformedHex => {
f.write_str("color format coordinates should be hexadecimal integers but are not")
}
MalformedFloat => {
f.write_str("color format coordinates should be floating point numbers but are not")
}
TooManyCoordinates => {
f.write_str("color format should have 3 coordinates but has more")
}
WrongThemeColor => {
f.write_str("OSC escape sequence with color is for the wrong theme entry")
}
MalformedThemeColor => f.write_str("OSC escape sequence with color is malformed"),
}
}
}
impl core::error::Error for ColorFormatError {}
#[cfg(feature = "pyffi")]
impl From<ColorFormatError> for PyErr {
fn from(value: ColorFormatError) -> Self {
PyValueError::new_err(value.to_string())
}
}
#[derive(Clone, Copy, Debug)]
pub struct HiResColorantError;
impl core::fmt::Display for HiResColorantError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("unable to format high-resolution colorant as ANSI escape sequence")
}
}
impl core::error::Error for HiResColorantError {}
#[cfg(feature = "pyffi")]
impl From<HiResColorantError> for PyErr {
fn from(value: HiResColorantError) -> Self {
PyValueError::new_err(value.to_string())
}
}
use crate::theme::ThemeEntry;
#[derive(Clone, Copy, Debug)]
pub enum ThemeErrorKind {
AccessDevice,
WriteQuery(ThemeEntry),
ScanEscape(ThemeEntry),
ParseColor(ThemeEntry),
}
#[derive(Debug)]
pub struct ThemeError {
kind: ThemeErrorKind,
source: Option<Box<dyn core::error::Error + Send + Sync>>,
}
impl ThemeError {
pub fn new(kind: ThemeErrorKind, source: Box<dyn core::error::Error + Send + Sync>) -> Self {
Self {
kind,
source: Some(source),
}
}
}
impl From<ThemeError> for std::io::Error {
fn from(value: ThemeError) -> Self {
std::io::Error::other(value)
}
}
impl core::fmt::Display for ThemeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let entry = match self.kind {
ThemeErrorKind::AccessDevice => return f.write_str("could not access terminal device"),
ThemeErrorKind::WriteQuery(entry) => {
f.write_str("could not write query for ")?;
entry
}
ThemeErrorKind::ScanEscape(entry) => {
f.write_str("could not parse ANSI escape sequence for ")?;
entry
}
ThemeErrorKind::ParseColor(entry) => {
f.write_str("could not parse color for ")?;
entry
}
};
f.write_str(entry.name())
}
}
impl core::error::Error for ThemeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
self.source.as_deref().map(|e| e as _)
}
}