From e674fd7e909c273c36952f01829544a2efc11c92 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 4 May 2022 22:14:57 +0200 Subject: New raw theme & nicer debug representation --- src/eval/func.rs | 10 +++---- src/eval/value.rs | 22 +++++++------- src/geom/paint.rs | 5 ++-- src/library/text/raw.rs | 76 ++++++++++++++++++++++++++++++++++++++----------- src/parse/mod.rs | 30 +++++++++++++------ src/syntax/highlight.rs | 6 ++-- 6 files changed, 101 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/eval/func.rs b/src/eval/func.rs index 7e4040b6..b72e9f18 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -1,4 +1,4 @@ -use std::fmt::{self, Debug, Formatter, Write}; +use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::sync::Arc; @@ -119,12 +119,10 @@ impl Func { impl Debug for Func { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(" f.write_str(name), + None => f.write_str("(..) => {..}"), } - f.write_char('>') } } diff --git a/src/eval/value.rs b/src/eval/value.rs index fc54cbce..b5607cfd 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -122,8 +122,9 @@ impl Value { Value::Content(v) => v, // For values which can't be shown "naturally", we return the raw - // representation. - v => Content::show(RawNode { text: v.repr(), block: false }), + // representation with typst code syntax highlighting. + v => Content::show(RawNode { text: v.repr(), block: false }) + .styled(RawNode::LANG, Some("typc".into())), } } } @@ -149,7 +150,7 @@ impl Debug for Value { Self::Fraction(v) => Debug::fmt(v, f), Self::Color(v) => Debug::fmt(v, f), Self::Str(v) => Debug::fmt(v, f), - Self::Content(_) => f.pad(""), + Self::Content(_) => f.pad("[...]"), Self::Array(v) => Debug::fmt(v, f), Self::Dict(v) => Debug::fmt(v, f), Self::Func(v) => Debug::fmt(v, f), @@ -720,7 +721,10 @@ mod tests { "30% + 56.69pt", ); test(Fraction::one() * 7.55, "7.55fr"); - test(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101"); + test( + Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), + "rgb(\"#010101\")", + ); // Collections. test("hello", r#""hello""#); @@ -734,13 +738,9 @@ mod tests { test(dict!["one" => 1], "(one: 1)"); test(dict!["two" => false, "one" => 1], "(one: 1, two: false)"); - // Functions. - test( - Func::from_fn("nil", |_, _| Ok(Value::None)), - "", - ); - - // Dynamics. + // Functions, content and dynamics. + test(Content::Text("a".into()), "[...]"); + test(Func::from_fn("nil", |_, _| Ok(Value::None)), "nil"); test(Dynamic::new(1), "1"); } } diff --git a/src/geom/paint.rs b/src/geom/paint.rs index 351ef443..9b310249 100644 --- a/src/geom/paint.rs +++ b/src/geom/paint.rs @@ -154,7 +154,7 @@ impl FromStr for RgbaColor { impl From for RgbaColor { fn from(color: SynColor) -> Self { - Self::new(color.r, color.b, color.g, color.a) + Self::new(color.r, color.g, color.b, color.a) } } @@ -167,10 +167,11 @@ impl Debug for RgbaColor { self.r, self.g, self.b, self.a, )?; } else { - write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?; + write!(f, "rgb(\"#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?; if self.a != 255 { write!(f, "{:02x}", self.a)?; } + write!(f, "\")")?; } Ok(()) } diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index c711aa16..d5a3aa95 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -1,20 +1,17 @@ +use std::sync::Arc; + use once_cell::sync::Lazy; use syntect::easy::HighlightLines; -use syntect::highlighting::{FontStyle, Highlighter, Style, Theme, ThemeSet}; +use syntect::highlighting::{ + Color, FontStyle, Highlighter, Style, StyleModifier, Theme, ThemeItem, ThemeSettings, +}; use syntect::parsing::SyntaxSet; use super::{FontFamily, Hyphenate, TextNode, Toggle}; use crate::library::layout::BlockSpacing; use crate::library::prelude::*; use crate::source::SourceId; -use crate::syntax::{self, RedNode}; - -/// The lazily-loaded theme used for syntax highlighting. -static THEME: Lazy = - Lazy::new(|| ThemeSet::load_defaults().themes.remove("InspiredGitHub").unwrap()); - -/// The lazily-loaded syntect syntax definitions. -static SYNTAXES: Lazy = Lazy::new(|| SyntaxSet::load_defaults_newlines()); +use crate::syntax::{self, GreenNode, NodeKind, RedNode}; /// Monospaced text with optional syntax highlighting. #[derive(Debug, Hash)] @@ -63,7 +60,7 @@ impl Show for RawNode { } fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { - let lang = styles.get(Self::LANG).as_ref(); + let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase()); let foreground = THEME .settings .foreground @@ -71,15 +68,19 @@ impl Show for RawNode { .unwrap_or(Color::BLACK) .into(); - let mut realized = if matches!( - lang.map(|s| s.to_lowercase()).as_deref(), - Some("typ" | "typst") - ) { - let mut seq = vec![]; - let green = crate::parse::parse(&self.text); - let red = RedNode::from_root(green, SourceId::from_raw(0)); + let mut realized = if matches!(lang.as_deref(), Some("typ" | "typst" | "typc")) { + let root = match lang.as_deref() { + Some("typc") => { + let children = crate::parse::parse_code(&self.text); + Arc::new(GreenNode::with_children(NodeKind::CodeBlock, children)) + } + _ => crate::parse::parse(&self.text), + }; + + let red = RedNode::from_root(root, SourceId::from_raw(0)); let highlighter = Highlighter::new(&THEME); + let mut seq = vec![]; syntax::highlight_syntect(red.as_ref(), &highlighter, &mut |range, style| { seq.push(styled(&self.text[range], foreground, style)); }); @@ -159,3 +160,44 @@ fn styled(piece: &str, foreground: Paint, style: Style) -> Content { body.styled_with_map(styles) } + +/// The lazily-loaded syntect syntax definitions. +static SYNTAXES: Lazy = Lazy::new(|| SyntaxSet::load_defaults_newlines()); + +/// The lazily-loaded theme used for syntax highlighting. +#[rustfmt::skip] +static THEME: Lazy = Lazy::new(|| Theme { + name: Some("Typst Light".into()), + author: Some("The Typst Project Developers".into()), + settings: ThemeSettings::default(), + scopes: vec![ + item("markup.bold", None, Some(FontStyle::BOLD)), + item("markup.italic", None, Some(FontStyle::ITALIC)), + item("markup.heading, entity.name.section", None, Some(FontStyle::BOLD)), + item("markup.raw", Some("#818181"), None), + item("markup.list", Some("#8b41b1"), None), + item("comment", Some("#8a8a8a"), None), + item("keyword, constant.language, variable.language", Some("#d73a49"), None), + item("storage.type, storage.modifier", Some("#d73a49"), None), + item("entity.other", Some("#8b41b1"), None), + item("entity.name, variable.function, support", Some("#4b69c6"), None), + item("support.macro", Some("#16718d"), None), + item("meta.annotation", Some("#301414"), None), + item("constant", Some("#b60157"), None), + item("string", Some("#298e0d"), None), + item("punctuation.shortcut", Some("#1d6c76"), None), + item("constant.character.escape", Some("#1d6c76"), None), + ], +}); + +/// Create a syntect theme item. +fn item(scope: &str, color: Option<&str>, font_style: Option) -> ThemeItem { + ThemeItem { + scope: scope.parse().unwrap(), + style: StyleModifier { + foreground: color.map(|s| s.parse().unwrap()), + background: None, + font_style, + }, + } +} diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 9f4860e7..7811482b 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -26,6 +26,13 @@ pub fn parse(src: &str) -> Arc { } } +/// Parse code directly, only used for syntax highlighting. +pub fn parse_code(src: &str) -> Vec { + let mut p = Parser::new(src, TokenMode::Code); + code(&mut p); + p.finish() +} + /// Reparse a code block. /// /// Returns `Some` if all of the input was consumed. @@ -696,18 +703,23 @@ fn params(p: &mut Parser, marker: Marker) { fn code_block(p: &mut Parser) { p.perform(NodeKind::CodeBlock, |p| { p.start_group(Group::Brace); - while !p.eof() { - p.start_group(Group::Expr); - if expr(p).is_ok() && !p.eof() { - p.expected("semicolon or line break"); - } - p.end_group(); + code(p); + p.end_group(); + }); +} - // Forcefully skip over newlines since the group's contents can't. - p.eat_while(|t| matches!(t, NodeKind::Space(_))); +/// Parse expressions. +fn code(p: &mut Parser) { + while !p.eof() { + p.start_group(Group::Expr); + if expr(p).is_ok() && !p.eof() { + p.expected("semicolon or line break"); } p.end_group(); - }); + + // Forcefully skip over newlines since the group's contents can't. + p.eat_while(|t| matches!(t, NodeKind::Space(_))); + } } // Parse a content block: `[...]`. diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs index 8e62424f..dae379ac 100644 --- a/src/syntax/highlight.rs +++ b/src/syntax/highlight.rs @@ -95,7 +95,7 @@ pub enum Category { /// A function. Function, /// An interpolated variable in markup. - Variable, + Interpolated, /// An invalid node. Invalid, } @@ -178,7 +178,7 @@ impl Category { NodeKind::None => Some(Category::None), NodeKind::Auto => Some(Category::Auto), NodeKind::Ident(_) => match parent.kind() { - NodeKind::Markup(_) => Some(Category::Variable), + NodeKind::Markup(_) => Some(Category::Interpolated), NodeKind::FuncCall => Some(Category::Function), NodeKind::MethodCall if i > 0 => Some(Category::Function), NodeKind::ClosureExpr if i == 0 => Some(Category::Function), @@ -263,7 +263,7 @@ impl Category { Self::Number => "constant.numeric.typst", Self::String => "string.quoted.double.typst", Self::Function => "entity.name.function.typst", - Self::Variable => "variable.parameter.typst", + Self::Interpolated => "entity.other.interpolated.typst", Self::Invalid => "invalid.typst", } } -- cgit v1.2.3