reporting: generalise text styles to work with HTML as well as ANSI

This commit is contained in:
Brian Carroll 2022-03-17 09:31:14 +00:00
parent dca9404772
commit 0d7a7fe34f
2 changed files with 116 additions and 65 deletions

View file

@ -128,59 +128,110 @@ impl<'b> Report<'b> {
} }
} }
pub struct Palette<'a> { /// This struct is a combination of several things
pub primary: &'a str, /// 1. A set of StyleCodes suitable for the platform we're running on (web or terminal)
pub code_block: &'a str, /// 2. A set of colors we decided to use
pub keyword: &'a str, /// 3. A mapping from UI elements to the styles we use for them
pub variable: &'a str, /// Note: This should really be called Theme! Usually a "palette" is just (2).
pub type_variable: &'a str, pub struct Palette {
pub structure: &'a str, pub primary: &'static str,
pub alias: &'a str, pub code_block: &'static str,
pub opaque: &'a str, pub keyword: &'static str,
pub error: &'a str, pub variable: &'static str,
pub line_number: &'a str, pub type_variable: &'static str,
pub header: &'a str, pub structure: &'static str,
pub gutter_bar: &'a str, pub alias: &'static str,
pub module_name: &'a str, pub opaque: &'static str,
pub binop: &'a str, pub error: &'static str,
pub typo: &'a str, pub line_number: &'static str,
pub typo_suggestion: &'a str, pub header: &'static str,
pub parser_suggestion: &'a str, pub gutter_bar: &'static str,
pub module_name: &'static str,
pub binop: &'static str,
pub typo: &'static str,
pub typo_suggestion: &'static str,
pub parser_suggestion: &'static str,
pub bold: &'static str,
pub underline: &'static str,
pub reset: &'static str,
} }
pub const DEFAULT_PALETTE: Palette = Palette { /// Set the default styles for various semantic elements,
primary: WHITE_CODE, /// given a set of StyleCodes for a platform (web or terminal).
code_block: WHITE_CODE, const fn default_palette_from_style_codes(codes: StyleCodes) -> Palette {
keyword: GREEN_CODE, Palette {
variable: BLUE_CODE, primary: codes.white,
type_variable: YELLOW_CODE, code_block: codes.white,
structure: GREEN_CODE, keyword: codes.green,
alias: YELLOW_CODE, variable: codes.blue,
opaque: YELLOW_CODE, type_variable: codes.yellow,
error: RED_CODE, structure: codes.green,
line_number: CYAN_CODE, alias: codes.yellow,
header: CYAN_CODE, opaque: codes.yellow,
gutter_bar: CYAN_CODE, error: codes.red,
module_name: GREEN_CODE, line_number: codes.cyan,
binop: GREEN_CODE, header: codes.cyan,
typo: YELLOW_CODE, gutter_bar: codes.cyan,
typo_suggestion: GREEN_CODE, module_name: codes.green,
parser_suggestion: YELLOW_CODE, binop: codes.green,
typo: codes.yellow,
typo_suggestion: codes.green,
parser_suggestion: codes.yellow,
bold: codes.bold,
underline: codes.underline,
reset: codes.reset,
}
}
pub const DEFAULT_PALETTE: Palette = default_palette_from_style_codes(ANSI_STYLE_CODES);
pub const DEFAULT_PALETTE_HTML: Palette = default_palette_from_style_codes(HTML_STYLE_CODES);
/// A machine-readable format for text styles (colors and other styles)
pub struct StyleCodes {
pub red: &'static str,
pub green: &'static str,
pub yellow: &'static str,
pub blue: &'static str,
pub magenta: &'static str,
pub cyan: &'static str,
pub white: &'static str,
pub bold: &'static str,
pub underline: &'static str,
pub reset: &'static str,
}
pub const ANSI_STYLE_CODES: StyleCodes = StyleCodes {
red: "\u{001b}[31m",
green: "\u{001b}[32m",
yellow: "\u{001b}[33m",
blue: "\u{001b}[34m",
magenta: "\u{001b}[35m",
cyan: "\u{001b}[36m",
white: "\u{001b}[37m",
bold: "\u{001b}[1m",
underline: "\u{001b}[4m",
reset: "\u{001b}[0m",
}; };
pub const RED_CODE: &str = "\u{001b}[31m"; macro_rules! html_color {
pub const GREEN_CODE: &str = "\u{001b}[32m"; ($name: expr) => {
pub const YELLOW_CODE: &str = "\u{001b}[33m"; concat!("<span style='color: ", $name, "'>")
pub const BLUE_CODE: &str = "\u{001b}[34m"; };
pub const MAGENTA_CODE: &str = "\u{001b}[35m"; }
pub const CYAN_CODE: &str = "\u{001b}[36m";
pub const WHITE_CODE: &str = "\u{001b}[37m";
pub const BOLD_CODE: &str = "\u{001b}[1m"; pub const HTML_STYLE_CODES: StyleCodes = StyleCodes {
red: html_color!("red"),
pub const UNDERLINE_CODE: &str = "\u{001b}[4m"; green: html_color!("green"),
yellow: html_color!("yellow"),
pub const RESET_CODE: &str = "\u{001b}[0m"; blue: html_color!("blue"),
magenta: html_color!("magenta"),
cyan: html_color!("cyan"),
white: html_color!("white"),
bold: "<span style='font-weight: bold'",
underline: "<span style='text-decoration: underline'",
reset: "</span>",
};
// define custom allocator struct so we can `impl RocDocAllocator` custom helpers // define custom allocator struct so we can `impl RocDocAllocator` custom helpers
pub struct RocDocAllocator<'a> { pub struct RocDocAllocator<'a> {
@ -742,7 +793,7 @@ impl<W> CiWrite<W> {
/// Render with fancy formatting /// Render with fancy formatting
pub struct ColorWrite<'a, W> { pub struct ColorWrite<'a, W> {
style_stack: Vec<Annotation>, style_stack: Vec<Annotation>,
palette: &'a Palette<'a>, palette: &'a Palette,
upstream: W, upstream: W,
} }
@ -858,10 +909,10 @@ where
use Annotation::*; use Annotation::*;
match annotation { match annotation {
Emphasized => { Emphasized => {
self.write_str(BOLD_CODE)?; self.write_str(self.palette.bold)?;
} }
Url | Tip => { Url | Tip => {
self.write_str(UNDERLINE_CODE)?; self.write_str(self.palette.underline)?;
} }
PlainText => { PlainText => {
self.write_str(self.palette.primary)?; self.write_str(self.palette.primary)?;
@ -929,7 +980,7 @@ where
Emphasized | Url | TypeVariable | Alias | Symbol | BinOp | Error | GutterBar Emphasized | Url | TypeVariable | Alias | Symbol | BinOp | Error | GutterBar
| Typo | TypoSuggestion | ParserSuggestion | Structure | CodeBlock | PlainText | Typo | TypoSuggestion | ParserSuggestion | Structure | CodeBlock | PlainText
| LineNumber | Tip | Module | Header | Keyword => { | LineNumber | Tip | Module | Header | Keyword => {
self.write_str(RESET_CODE)?; self.write_str(self.palette.reset)?;
} }
TypeBlock | GlobalTag | PrivateTag | Opaque | RecordField => { /* nothing yet */ } TypeBlock | GlobalTag | PrivateTag | Opaque | RecordField => { /* nothing yet */ }

View file

@ -12,14 +12,14 @@ mod test_reporting {
use crate::helpers::test_home; use crate::helpers::test_home;
use crate::helpers::{can_expr, infer_expr, CanExprOut, ParseErrOut}; use crate::helpers::{can_expr, infer_expr, CanExprOut, ParseErrOut};
use bumpalo::Bump; use bumpalo::Bump;
use indoc::indoc;
use roc_module::symbol::{Interns, ModuleId}; use roc_module::symbol::{Interns, ModuleId};
use roc_mono::ir::{Procs, Stmt, UpdateModeIds}; use roc_mono::ir::{Procs, Stmt, UpdateModeIds};
use roc_mono::layout::LayoutCache; use roc_mono::layout::LayoutCache;
use roc_region::all::LineInfo; use roc_region::all::LineInfo;
use roc_reporting::report::{ use roc_reporting::report::{
can_problem, mono_problem, parse_problem, type_problem, Report, Severity, BLUE_CODE, can_problem, mono_problem, parse_problem, type_problem, Report, Severity, ANSI_STYLE_CODES,
BOLD_CODE, CYAN_CODE, DEFAULT_PALETTE, GREEN_CODE, MAGENTA_CODE, RED_CODE, RESET_CODE, DEFAULT_PALETTE,
UNDERLINE_CODE, WHITE_CODE, YELLOW_CODE,
}; };
use roc_reporting::report::{RocDocAllocator, RocDocBuilder}; use roc_reporting::report::{RocDocAllocator, RocDocBuilder};
use roc_solve::solve; use roc_solve::solve;
@ -288,16 +288,16 @@ mod test_reporting {
} }
fn human_readable(str: &str) -> String { fn human_readable(str: &str) -> String {
str.replace(RED_CODE, "<red>") str.replace(ANSI_STYLE_CODES.red, "<red>")
.replace(WHITE_CODE, "<white>") .replace(ANSI_STYLE_CODES.white, "<white>")
.replace(BLUE_CODE, "<blue>") .replace(ANSI_STYLE_CODES.blue, "<blue>")
.replace(YELLOW_CODE, "<yellow>") .replace(ANSI_STYLE_CODES.yellow, "<yellow>")
.replace(GREEN_CODE, "<green>") .replace(ANSI_STYLE_CODES.green, "<green>")
.replace(CYAN_CODE, "<cyan>") .replace(ANSI_STYLE_CODES.cyan, "<cyan>")
.replace(MAGENTA_CODE, "<magenta>") .replace(ANSI_STYLE_CODES.magenta, "<magenta>")
.replace(RESET_CODE, "<reset>") .replace(ANSI_STYLE_CODES.reset, "<reset>")
.replace(BOLD_CODE, "<bold>") .replace(ANSI_STYLE_CODES.bold, "<bold>")
.replace(UNDERLINE_CODE, "<underline>") .replace(ANSI_STYLE_CODES.underline, "<underline>")
} }
#[test] #[test]