mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-19 13:36:32 +01:00
improve and move theming traits
move pretty_print.rs from mers to mers_lib
This commit is contained in:
@@ -8,6 +8,9 @@ use line_span::LineSpans;
|
||||
|
||||
#[cfg(feature = "parse")]
|
||||
use crate::parsing::Source;
|
||||
use crate::theme::ThemeGen;
|
||||
|
||||
pub mod themes;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SourcePos(pub(crate) usize);
|
||||
@@ -62,6 +65,9 @@ pub enum EColor {
|
||||
BackslashEscapeUnknown,
|
||||
BackslashEscapeEOF,
|
||||
StringEOF,
|
||||
TypeEOF,
|
||||
/// `&[Int/String` (notice the missing `]`)
|
||||
BracketedRefTypeNoClosingBracket,
|
||||
IfConditionNotBool,
|
||||
ChainWithNonFunction,
|
||||
Function,
|
||||
@@ -92,115 +98,24 @@ pub enum EColor {
|
||||
InCodePositionLine,
|
||||
}
|
||||
|
||||
pub trait Theme<T> {
|
||||
fn color(&self, text: &str, color: EColor, t: &mut T);
|
||||
}
|
||||
pub trait ThemeTo<T>: Theme<T> {
|
||||
fn color_to(&self, text: &str, color: EColor) -> T;
|
||||
}
|
||||
impl<T: Theme<String> + ?Sized> ThemeTo<String> for T {
|
||||
fn color_to(&self, text: &str, color: EColor) -> String {
|
||||
let mut t = String::new();
|
||||
self.color(text, color, &mut t);
|
||||
t
|
||||
}
|
||||
}
|
||||
pub trait ETheme: ThemeGen<C = EColor, T = String> {}
|
||||
impl<T: ThemeGen<C = EColor, T = String>> ETheme for T {}
|
||||
|
||||
pub fn colorize_str(
|
||||
message: &Vec<(String, Option<EColor>)>,
|
||||
theme: &(impl Theme<String> + ?Sized),
|
||||
theme: &(impl ETheme + ?Sized),
|
||||
) -> String {
|
||||
let mut t = String::new();
|
||||
colorize_gen(message, &mut t, |t, a| a.push_str(t), theme);
|
||||
t
|
||||
}
|
||||
pub fn colorize_gen<T>(
|
||||
message: &Vec<(String, Option<EColor>)>,
|
||||
t: &mut T,
|
||||
direct: impl Fn(&str, &mut T),
|
||||
theme: &(impl Theme<T> + ?Sized),
|
||||
) {
|
||||
for (text, color) in message {
|
||||
if let Some(color) = *color {
|
||||
theme.color(text, color, t)
|
||||
theme.color(text, color, &mut t)
|
||||
} else {
|
||||
direct(text, t)
|
||||
theme.nocolor(text, &mut t)
|
||||
}
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
pub struct NoTheme;
|
||||
impl Theme<String> for NoTheme {
|
||||
fn color(&self, text: &str, _color: EColor, t: &mut String) {
|
||||
t.push_str(text);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecolor-term")]
|
||||
pub struct TermDefaultTheme;
|
||||
#[cfg(feature = "ecolor-term")]
|
||||
impl Theme<String> for TermDefaultTheme {
|
||||
fn color(&self, text: &str, color: EColor, t: &mut String) {
|
||||
use colored::{Color, Colorize};
|
||||
t.push_str(
|
||||
&text
|
||||
.color(match color {
|
||||
EColor::Indent(n) => match n % 6 {
|
||||
0 => Color::Red,
|
||||
1 => Color::Green,
|
||||
2 => Color::Yellow,
|
||||
3 => Color::Blue,
|
||||
4 => Color::Magenta,
|
||||
_ => Color::Cyan,
|
||||
},
|
||||
|
||||
EColor::UnknownVariable => Color::Red,
|
||||
|
||||
EColor::WhitespaceAfterHashtag => Color::Red,
|
||||
EColor::HashUnknown => Color::Red,
|
||||
EColor::HashIncludeCantLoadFile => Color::Red,
|
||||
EColor::HashIncludeNotAString => Color::Red,
|
||||
EColor::HashIncludeErrorInIncludedFile => Color::Red,
|
||||
|
||||
EColor::BackslashEscapeUnknown => Color::Red,
|
||||
EColor::BackslashEscapeEOF => Color::Red,
|
||||
EColor::StringEOF => Color::Red,
|
||||
|
||||
EColor::IfConditionNotBool => Color::Red,
|
||||
EColor::ChainWithNonFunction => Color::Yellow,
|
||||
|
||||
EColor::Function => Color::BrightMagenta,
|
||||
EColor::FunctionArgument => Color::BrightBlue,
|
||||
|
||||
EColor::InitFrom
|
||||
| EColor::AssignFrom
|
||||
| EColor::AsTypeStatementWithTooBroadType => Color::BrightCyan,
|
||||
EColor::InitTo | EColor::AssignTo | EColor::AsTypeTypeAnnotation => {
|
||||
Color::Green
|
||||
}
|
||||
EColor::AssignTargetNonReference => Color::BrightYellow,
|
||||
|
||||
EColor::BadCharInTupleType => Color::Red,
|
||||
EColor::BadCharInFunctionType => Color::Red,
|
||||
EColor::BadTypeFromParsed => Color::Blue,
|
||||
EColor::TypeAnnotationNoClosingBracket => Color::Blue,
|
||||
|
||||
EColor::TryBadSyntax => Color::Red,
|
||||
EColor::TryNoFunctionFound => Color::Red,
|
||||
EColor::TryNotAFunction => Color::Red,
|
||||
EColor::TryUnusedFunction1 => Color::Red,
|
||||
EColor::TryUnusedFunction2 => Color::BrightRed,
|
||||
EColor::CustomTypeTestFailed => Color::BrightRed,
|
||||
|
||||
EColor::StacktraceDescend => Color::Yellow,
|
||||
EColor::StacktraceDescendHashInclude => Color::Red,
|
||||
EColor::MaximumRuntimeExceeded => Color::BrightYellow,
|
||||
|
||||
EColor::InCodePositionLine => Color::BrightBlack,
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum CheckErrorComponent {
|
||||
Message(Vec<(String, Option<EColor>)>),
|
||||
@@ -211,7 +126,7 @@ pub enum CheckErrorComponent {
|
||||
pub struct CheckErrorHRConfig {
|
||||
color_index_ptr: Rc<AtomicU32>,
|
||||
color_index: u32,
|
||||
theme: Rc<dyn Theme<String>>,
|
||||
theme: Rc<dyn ETheme>,
|
||||
is_inner: bool,
|
||||
style: u8,
|
||||
idt_start: String,
|
||||
@@ -335,7 +250,7 @@ impl CheckErrorHRConfig {
|
||||
#[cfg(feature = "parse")]
|
||||
pub struct CheckErrorDisplay<'a> {
|
||||
e: &'a CheckError,
|
||||
theme: Rc<dyn Theme<String>>,
|
||||
theme: Rc<dyn ETheme>,
|
||||
pub show_comments: bool,
|
||||
}
|
||||
#[cfg(feature = "parse")]
|
||||
@@ -409,7 +324,7 @@ impl CheckError {
|
||||
self.add_mut(CheckErrorComponent::Source(s))
|
||||
}
|
||||
#[cfg(feature = "parse")]
|
||||
pub fn display<'a>(&'a self, theme: impl Theme<String> + 'static) -> CheckErrorDisplay<'a> {
|
||||
pub fn display<'a>(&'a self, theme: impl ETheme + 'static) -> CheckErrorDisplay<'a> {
|
||||
CheckErrorDisplay {
|
||||
e: self,
|
||||
theme: Rc::new(theme),
|
||||
@@ -419,13 +334,13 @@ impl CheckError {
|
||||
/// Like `display`, but doesn't use any theme (doesn't colorize its output)
|
||||
#[cfg(feature = "parse")]
|
||||
pub fn display_notheme<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
||||
self.display(NoTheme)
|
||||
self.display(themes::NoTheme)
|
||||
}
|
||||
/// Like `display`, but uses the default terminal theme
|
||||
#[cfg(feature = "parse")]
|
||||
#[cfg(feature = "ecolor-term")]
|
||||
pub fn display_term<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
||||
self.display(TermDefaultTheme)
|
||||
self.display(themes::TermDefaultTheme)
|
||||
}
|
||||
/// will, unless empty, end in a newline
|
||||
#[cfg(feature = "parse")]
|
||||
@@ -435,7 +350,7 @@ impl CheckError {
|
||||
cfg: &CheckErrorHRConfig,
|
||||
) -> std::fmt::Result {
|
||||
const ADD_RIGHT_BITS: bool = false;
|
||||
use crate::parsing::SourceFrom;
|
||||
use crate::{parsing::SourceFrom, theme::ThemeTo};
|
||||
|
||||
let len = self.0.len();
|
||||
for (i, component) in self.0.iter().enumerate() {
|
||||
|
||||
177
mers_lib/src/errors/themes.rs
Normal file
177
mers_lib/src/errors/themes.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
use super::{EColor, ThemeGen};
|
||||
|
||||
pub struct NoTheme;
|
||||
impl ThemeGen for NoTheme {
|
||||
type C = EColor;
|
||||
type T = String;
|
||||
fn color(&self, text: &str, _color: EColor, t: &mut String) {
|
||||
self.nocolor(text, t);
|
||||
}
|
||||
fn nocolor(&self, text: &str, t: &mut String) {
|
||||
t.push_str(text);
|
||||
}
|
||||
}
|
||||
|
||||
/// converts an `EColor` to the color type you need for your theme.
|
||||
/// This theme is optimized for ANSI terminal colors,
|
||||
/// as most of mers' colored output will be printed to a terminal.
|
||||
pub fn default_theme<C>(
|
||||
color: EColor,
|
||||
gray: C,
|
||||
red: C,
|
||||
red_bright: C,
|
||||
green: C,
|
||||
green_bright: C,
|
||||
yellow: C,
|
||||
yellow_bright: C,
|
||||
blue: C,
|
||||
blue_bright: C,
|
||||
magenta: C,
|
||||
magenta_bright: C,
|
||||
cyan: C,
|
||||
cyan_bright: C,
|
||||
) -> Option<C> {
|
||||
if let Indent(n) = color {
|
||||
return Some(match n % 7 {
|
||||
1 => red,
|
||||
2 => green,
|
||||
3 => yellow,
|
||||
4 => blue,
|
||||
5 => magenta,
|
||||
6 => cyan,
|
||||
_ => return None,
|
||||
});
|
||||
}
|
||||
let hard_err = red;
|
||||
let type_right = blue;
|
||||
let type_wrong = magenta;
|
||||
let type_wrong_b = magenta_bright;
|
||||
let function = blue_bright; // used in combination with TYPE_WRONG
|
||||
let missing = cyan;
|
||||
let runtime = yellow;
|
||||
let runtime_b = yellow_bright;
|
||||
let unused = green;
|
||||
let unused_b = green_bright;
|
||||
drop(red_bright);
|
||||
drop(cyan_bright);
|
||||
use EColor::*;
|
||||
Some(match color {
|
||||
Indent(_) => unreachable!(),
|
||||
|
||||
// macros (#...)
|
||||
WhitespaceAfterHashtag
|
||||
| HashUnknown
|
||||
| HashIncludeCantLoadFile
|
||||
| HashIncludeNotAString
|
||||
| HashIncludeErrorInIncludedFile
|
||||
| StacktraceDescendHashInclude => hard_err,
|
||||
|
||||
// -- bad syntax --
|
||||
UnknownVariable => hard_err,
|
||||
BackslashEscapeUnknown => hard_err,
|
||||
BackslashEscapeEOF | StringEOF | TypeEOF => missing,
|
||||
BadCharInTupleType => hard_err,
|
||||
BadCharInFunctionType => hard_err,
|
||||
TryBadSyntax => hard_err,
|
||||
TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing,
|
||||
|
||||
BadTypeFromParsed => type_wrong_b,
|
||||
|
||||
// -- type-errors --
|
||||
IfConditionNotBool => type_wrong,
|
||||
TryNoFunctionFound => type_wrong_b,
|
||||
TryNotAFunction => type_wrong,
|
||||
TryUnusedFunction1 => unused,
|
||||
TryUnusedFunction2 => unused_b,
|
||||
|
||||
CustomTypeTestFailed => hard_err,
|
||||
|
||||
ChainWithNonFunction => type_wrong,
|
||||
|
||||
AssignTargetNonReference => type_wrong,
|
||||
|
||||
Function => function,
|
||||
FunctionArgument => type_wrong,
|
||||
|
||||
InitFrom | AssignFrom | AsTypeStatementWithTooBroadType => type_wrong,
|
||||
InitTo | AssignTo | AsTypeTypeAnnotation => type_right,
|
||||
|
||||
// -- runtime-errors --
|
||||
StacktraceDescend => runtime,
|
||||
MaximumRuntimeExceeded => runtime_b,
|
||||
|
||||
InCodePositionLine => gray,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecolor-term")]
|
||||
pub struct TermDefaultTheme;
|
||||
#[cfg(feature = "ecolor-term")]
|
||||
impl ThemeGen for TermDefaultTheme {
|
||||
type C = EColor;
|
||||
type T = String;
|
||||
fn color(&self, text: &str, color: EColor, t: &mut String) {
|
||||
use colored::Color::*;
|
||||
if let Some(color) = default_theme(
|
||||
color,
|
||||
BrightBlack,
|
||||
Red,
|
||||
BrightRed,
|
||||
Green,
|
||||
BrightGreen,
|
||||
Yellow,
|
||||
BrightYellow,
|
||||
Blue,
|
||||
BrightBlue,
|
||||
Magenta,
|
||||
BrightMagenta,
|
||||
Cyan,
|
||||
BrightCyan,
|
||||
) {
|
||||
use colored::Colorize;
|
||||
t.push_str(&text.color(color).to_string());
|
||||
} else {
|
||||
self.nocolor(text, t)
|
||||
}
|
||||
}
|
||||
fn nocolor(&self, text: &str, t: &mut String) {
|
||||
t.push_str(text);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecolor-html")]
|
||||
pub struct HtmlDefaultTheme;
|
||||
#[cfg(feature = "ecolor-html")]
|
||||
impl ThemeGen for HtmlDefaultTheme {
|
||||
type C = EColor;
|
||||
type T = String;
|
||||
fn color(&self, text: &str, color: EColor, t: &mut String) {
|
||||
if let Some(color) = default_theme(
|
||||
color,
|
||||
"Gray",
|
||||
"Crimson",
|
||||
"Red",
|
||||
"Green",
|
||||
"LimeGreen",
|
||||
"Gold",
|
||||
"Yellow",
|
||||
"RoyalBlue",
|
||||
"DeepSkyBlue",
|
||||
"Purple",
|
||||
"Orchid",
|
||||
"DarkCyan",
|
||||
"Turquoise",
|
||||
) {
|
||||
t.push_str("<span style=\"color:");
|
||||
t.push_str(color);
|
||||
t.push_str(";\">");
|
||||
html_escape::encode_text_to_string(text, t);
|
||||
t.push_str("</span>");
|
||||
} else {
|
||||
html_escape::encode_text_to_string(text, t);
|
||||
}
|
||||
}
|
||||
fn nocolor(&self, text: &str, t: &mut String) {
|
||||
t.push_str(text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user